1
# -*- coding: utf-8 -*-
3
# (c) Copyright 2003-2009 Hewlett-Packard Development Company, L.P.
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34
import hashlib # new in 2.5
37
return hashlib.sha1(s).hexdigest()
40
import sha # deprecated in 2.6/3.0
43
return sha.new(s).hexdigest()
46
import urllib # TODO: Replace with urllib2 (urllib is deprecated in Python 3.0)
51
from base.codes import *
52
from base import utils, pexpect
58
DISTRO_VER_UNKNOWN = '0.0'
60
MODE_INSTALLER = 0 # hplip-install/hp-setup
61
MODE_CHECK = 1 # hp-check
62
MODE_CREATE_DOCS = 2 # create_docs
69
DEPENDENCY_RUN_TIME = 1
70
DEPENDENCY_COMPILE_TIME = 2
71
DEPENDENCY_RUN_AND_COMPILE_TIME = 3
73
# Plug-in download errors
74
PLUGIN_INSTALL_ERROR_NONE = 0
75
PLUGIN_INSTALL_ERROR_PLUGIN_FILE_NOT_FOUND = 1
76
PLUGIN_INSTALL_ERROR_DIGITAL_SIG_NOT_FOUND = 2
77
PLUGIN_INSTALL_ERROR_DIGITAL_SIG_BAD = 3
78
PLUGIN_INSTALL_ERROR_PLUGIN_FILE_CHECKSUM_ERROR = 4
79
PLUGIN_INSTALL_ERROR_NO_NETWORK = 5
80
PLUGIN_INSTALL_ERROR_DIRECTORY_ERROR = 6
81
PLUGIN_INSTALL_ERROR_UNABLE_TO_RECV_KEYS = 7
84
PING_TARGET = "www.google.com"
85
HTTP_GET_TARGET = "http://www.google.com"
86
PLUGIN_FALLBACK_LOCATION = 'http://hplipopensource.com/hplip-web/plugin/'
91
"Continue?", # 2 (for zypper)
92
"passwor[dt]", # en/de/it/ru
103
# Mapping from patterns to probability contribution of pattern
104
# Example code from David Mertz' Text Processing in Python.
105
# Released in the Public Domain.
106
err_pats = {r'(?is)<TITLE>.*?(404|403).*?ERROR.*?</TITLE>': 0.95,
107
r'(?is)<TITLE>.*?ERROR.*?(404|403).*?</TITLE>': 0.95,
108
r'(?is)<TITLE>ERROR</TITLE>': 0.30,
109
r'(?is)<TITLE>.*?ERROR.*?</TITLE>': 0.10,
110
r'(?is)<META .*?(404|403).*?ERROR.*?>': 0.80,
111
r'(?is)<META .*?ERROR.*?(404|403).*?>': 0.80,
112
r'(?is)<TITLE>.*?File Not Found.*?</TITLE>': 0.80,
113
r'(?is)<TITLE>.*?Not Found.*?</TITLE>': 0.40,
114
r'(?is)<BODY.*(404|403).*</BODY>': 0.10,
115
r'(?is)<H1>.*?(404|403).*?</H1>': 0.15,
116
r'(?is)<BODY.*not found.*</BODY>': 0.10,
117
r'(?is)<H1>.*?not found.*?</H1>': 0.15,
118
r'(?is)<BODY.*the requested URL.*</BODY>': 0.10,
119
r'(?is)<BODY.*the page you requested.*</BODY>': 0.10,
120
r'(?is)<BODY.*page.{1,50}unavailable.*</BODY>': 0.10,
121
r'(?is)<BODY.*request.{1,50}unavailable.*</BODY>': 0.10,
122
r'(?i)does not exist': 0.10,
128
for s in EXPECT_WORD_LIST:
130
p = re.compile(s, re.I)
132
EXPECT_LIST.append(s)
134
EXPECT_LIST.append(p)
136
OK_PROCESS_LIST = ['adept-notifier',
141
CONFIGURE_ERRORS = { 1 : "General/unknown error",
142
2 : "libusb not found",
143
3 : "cups-devel not found",
144
4 : "libnetsnmp not found",
145
5 : "netsnmp-devel not found",
146
6 : "python-devel not found",
147
7 : "pthread-devel not found",
148
8 : "ppdev-devel not found",
149
9 : "libcups not found",
150
10 : "libm not found",
151
11 : "libusb-devel not found",
152
12 : "sane-backends-devel not found",
153
13 : "libdbus not found",
154
14 : "dbus-devel not found",
155
15 : "fax requires dbus support",
156
102 : "libjpeg not found",
157
103 : "jpeg-devel not found",
158
104 : "libdi not found",
163
from functools import update_wrapper
164
except ImportError: # using Python version < 2.5
166
def newf(*args, **kw):
167
log.debug("TRACE: func=%s(), args=%s, kwargs=%s" % (f.__name__, args, kw))
168
return f(*args, **kw)
169
newf.__name__ = f.__name__
170
newf.__dict__.update(f.__dict__)
171
newf.__doc__ = f.__doc__
172
newf.__module__ = f.__module__
174
else: # using Python 2.5+
176
def newf(*args, **kw):
177
log.debug("TRACE: func=%s(), args=%s, kwargs=%s" % (f.__name__, args, kw))
178
return f(*args, **kw)
179
return update_wrapper(newf, f)
183
class CoreInstall(object):
184
def __init__(self, mode=MODE_INSTALLER, ui_mode=INTERACTIVE_MODE, ui_toolkit='qt4'):
187
self.ui_mode = ui_mode
189
self.version_description, self.version_public, self.version_internal = '', '', ''
191
self.endian = utils.LITTLE_ENDIAN
192
self.distro, self.distro_name, self.distro_version = DISTRO_UNKNOWN, '', DISTRO_VER_UNKNOWN
193
self.distro_version_supported = False
194
self.install_location = '/usr'
195
self.hplip_present = False
196
self.have_dependencies = {}
197
self.native_cups = True
201
self.network_connected = False
202
self.ui_toolkit = ui_toolkit
205
self.plugin_path = "/tmp"
206
self.plugin_version = '0.0.0'
207
self.plugin_name = ''
208
self.reload_dbus = False
212
'distros' : TYPE_LIST,
214
'versions' : TYPE_LIST,
215
'display_name' : TYPE_STRING,
216
'alt_names': TYPE_LIST,
217
'display': TYPE_BOOL,
218
'notes': TYPE_STRING,
219
'package_mgrs': TYPE_LIST,
220
'package_mgr_cmd':TYPE_STRING,
221
'pre_install_cmd': TYPE_LIST,
222
'pre_depend_cmd': TYPE_LIST,
223
'post_depend_cmd': TYPE_LIST,
224
'hpoj_remove_cmd': TYPE_STRING,
225
'hplip_remove_cmd': TYPE_STRING,
226
'su_sudo': TYPE_STRING,
227
'ppd_install': TYPE_STRING,
228
'udev_mode_fix': TYPE_BOOL,
229
'ppd_dir': TYPE_STRING,
230
'drv_dir' : TYPE_STRING,
231
'fix_ppd_symlink': TYPE_BOOL,
232
'code_name': TYPE_STRING,
233
'supported': TYPE_BOOL, # Supported by installer
234
'release_date': TYPE_STRING,
235
'packages': TYPE_LIST,
236
'commands': TYPE_LIST,
237
'same_as_version' : TYPE_STRING,
238
'scan_supported' : TYPE_BOOL,
239
'fax_supported' : TYPE_BOOL,
240
'pcard_supported' : TYPE_BOOL,
241
'network_supported' : TYPE_BOOL,
242
'parallel_supported' : TYPE_BOOL,
243
'usb_supported' : TYPE_BOOL,
244
'packaged_version': TYPE_STRING, # Version of HPLIP pre-packaged in distro
245
'cups_path_with_bitness' : TYPE_BOOL,
246
'ui_toolkit' : TYPE_STRING, # qt3 or qt4 [or gtk] or none
247
'policykit' : TYPE_BOOL,
248
'native_cups' : TYPE_BOOL,
249
'package_available' : TYPE_BOOL,
250
'package_arch' : TYPE_LIST,
251
'add_user_to_group': TYPE_STRING,
252
'open_mdns_port' : TYPE_LIST, # command to use to open mdns multicast port 5353
253
'acl_rules' : TYPE_BOOL, # Use ACL uDEV rules (Ubuntu 9.10+)
254
'libdir_path' : TYPE_STRING,
258
# 'name': ('description', [<option list>])
260
'hplip': ("HP Linux Imaging and Printing System", ['base', 'network', 'gui_qt4',
261
'fax', 'scan', 'docs']),
264
self.selected_component = 'hplip'
267
# name: (<required>, "<display_name>", [<dependency list>]), ...
269
'base': (True, 'Required HPLIP base components (including hpcups)', []), # HPLIP
270
'network' : (False, 'Network/JetDirect I/O', []),
271
'gui_qt4' : (False, 'Graphical User Interfaces (Qt4)', []),
272
'fax' : (False, 'PC Send Fax support', []),
273
'scan': (False, 'Scanning support', []),
274
'docs': (False, 'HPLIP documentation (HTML)', []),
275
'policykit': (False, 'Administrative policy framework', []),
279
# holds whether the user has selected (turned on each option)
280
# initial values are defaults (for GUI only)
281
self.selected_options = {
289
'native_cups': False,
293
# 'name': (<required for option>, [<option list>], <display_name>, <check_func>, <runtime/compiletime>), ...
294
# Note: any change to the list of dependencies must be reflected in base/distros.py
295
self.dependencies = {
296
# Required base packages
297
'libjpeg': (True, ['base'], "libjpeg - JPEG library", self.check_libjpeg, DEPENDENCY_RUN_AND_COMPILE_TIME),
298
'libtool': (True, ['base'], "libtool - Library building support services", self.check_libtool, DEPENDENCY_COMPILE_TIME),
299
'cups' : (True, ['base'], 'CUPS - Common Unix Printing System', self.check_cups, DEPENDENCY_RUN_TIME),
300
'cups-devel': (True, ['base'], 'CUPS devel- Common Unix Printing System development files', self.check_cups_devel, DEPENDENCY_COMPILE_TIME),
301
'cups-image': (True, ['base'], "CUPS image - CUPS image development files", self.check_cups_image, DEPENDENCY_COMPILE_TIME),
302
'gcc' : (True, ['base'], 'gcc - GNU Project C and C++ Compiler', self.check_gcc, DEPENDENCY_COMPILE_TIME),
303
'make' : (True, ['base'], "make - GNU make utility to maintain groups of programs", self.check_make, DEPENDENCY_COMPILE_TIME),
304
'python-devel' : (True, ['base'], "Python devel - Python development files", self.check_python_devel, DEPENDENCY_COMPILE_TIME),
305
'libpthread' : (True, ['base'], "libpthread - POSIX threads library", self.check_libpthread, DEPENDENCY_RUN_AND_COMPILE_TIME),
306
'python2x': (True, ['base'], "Python 2.2 or greater - Python programming language", self.check_python2x, DEPENDENCY_RUN_AND_COMPILE_TIME),
307
'python-xml' : (True, ['base'], "Python XML libraries", self.check_python_xml, DEPENDENCY_RUN_TIME),
308
'gs': (True, ['base'], "GhostScript - PostScript and PDF language interpreter and previewer", self.check_gs, DEPENDENCY_RUN_TIME),
309
'libusb': (True, ['base'], "libusb - USB library", self.check_libusb, DEPENDENCY_RUN_AND_COMPILE_TIME),
311
# Optional base packages
312
'cups-ddk': (False, ['base'], "CUPS DDK - CUPS driver development kit", self.check_cupsddk, DEPENDENCY_RUN_TIME), # req. for .drv PPD installs
315
# Required scan packages
316
'sane': (True, ['scan'], "SANE - Scanning library", self.check_sane, DEPENDENCY_RUN_TIME),
317
'sane-devel' : (True, ['scan'], "SANE - Scanning library development files", self.check_sane_devel, DEPENDENCY_COMPILE_TIME),
319
# Optional scan packages
320
'xsane': (False, ['scan'], "xsane - Graphical scanner frontend for SANE", self.check_xsane, DEPENDENCY_RUN_TIME),
321
'scanimage': (False, ['scan'], "scanimage - Shell scanning program", self.check_scanimage, DEPENDENCY_RUN_TIME),
322
'pil': (False, ['scan'], "PIL - Python Imaging Library (required for commandline scanning with hp-scan)", self.check_pil, DEPENDENCY_RUN_TIME),
324
# Required fax packages
325
'python23': (True, ['fax'], "Python 2.3 or greater - Required for fax functionality", self.check_python23, DEPENDENCY_RUN_TIME),
326
'dbus': (True, ['fax'], "DBus - Message bus system", self.check_dbus, DEPENDENCY_RUN_AND_COMPILE_TIME),
327
'python-dbus': (True, ['fax'], "Python DBus - Python bindings for DBus", self.check_python_dbus, DEPENDENCY_RUN_TIME),
329
# Optional fax packages
330
'reportlab': (False, ['fax'], "Reportlab - PDF library for Python", self.check_reportlab, DEPENDENCY_RUN_TIME),
332
# Required and optional qt4 GUI packages
333
'pyqt4': (True, ['gui_qt4'], "PyQt 4- Qt interface for Python (for Qt version 4.x)", self.check_pyqt4, DEPENDENCY_RUN_TIME), # PyQt 4.x )
334
'pyqt4-dbus' : (True, ['gui_qt4'], "PyQt 4 DBus - DBus Support for PyQt4", self.check_pyqt4_dbus, DEPENDENCY_RUN_TIME),
335
'policykit': (False, ['gui_qt4'], "PolicyKit - Administrative policy framework", self.check_policykit, DEPENDENCY_RUN_TIME), # optional for non-sudo behavior of plugins (only optional for Qt4 option)
336
'python-notify' : (False, ['gui_qt4'], "Python libnotify - Python bindings for the libnotify Desktop notifications", self.check_pynotify, DEPENDENCY_RUN_TIME), # Optional for libnotify style popups from hp-systray
338
# Required network I/O packages
339
'libnetsnmp-devel': (True, ['network'], "libnetsnmp-devel - SNMP networking library development files", self.check_libnetsnmp, DEPENDENCY_RUN_AND_COMPILE_TIME),
340
'libcrypto': (True, ['network'], "libcrypto - OpenSSL cryptographic library", self.check_libcrypto, DEPENDENCY_RUN_AND_COMPILE_TIME),
343
for opt in self.options:
345
for d in self.dependencies:
346
if opt in self.dependencies[d][1]:
347
self.options[opt][2].append(d)
351
self.distros_index = {}
352
for d in self.distros:
353
self.distros_index[self.distros[d]['index']] = d
356
def init(self, callback=None):
357
if callback is not None:
358
callback("Init...\n")
362
# Package manager names
363
self.package_mgrs = []
364
for d in self.distros:
367
for a in self.distros[d].get('package_mgrs', []):
368
if a and a not in self.package_mgrs:
369
self.package_mgrs.append(a)
371
self.version_description, self.version_public, self.version_internal = self.get_hplip_version()
372
log.debug("HPLIP Description=%s Public version=%s Internal version = %s" %
373
(self.version_description, self.version_public, self.version_internal))
376
# is each dependency satisfied?
377
# start with each one 'No'
378
for d in self.dependencies:
380
self.have_dependencies[d] = False
383
self.distro_changed()
385
if callback is not None:
386
callback("Distro: %s\n" % self.distro)
388
self.check_dependencies(callback)
390
for d in self.dependencies:
393
log.debug("have %s = %s" % (d, self.have_dependencies[d]))
395
if callback is not None:
396
callback("Result: %s = %s\n" % (d, self.have_dependencies[d]))
398
pid, cmdline = self.check_pkg_mgr()
400
log.debug("Running package manager: %s (%d)" % (cmdline, pid) )
402
self.bitness = utils.getBitness()
403
log.debug("Bitness = %d" % self.bitness)
407
self.endian = utils.getEndian()
408
log.debug("Endian = %d" % self.endian)
412
self.distro_name = self.distros_index[self.distro]
413
self.distro_version_supported = self.get_distro_ver_data('supported', False)
415
log.debug("Distro = %s Distro Name = %s Display Name= %s Version = %s Supported = %s" %
416
(self.distro, self.distro_name, self.distros[self.distro_name]['display_name'],
417
self.distro_version, self.distro_version_supported))
421
self.hplip_present = self.check_hplip()
422
log.debug("HPLIP (prev install) = %s" % self.hplip_present)
424
status, output = self.run('cups-config --version')
425
self.cups_ver = output.strip()
426
log.debug("CUPS version = %s" % self.cups_ver)
428
if self.distro_name == "ubuntu":
429
self.reload_dbus = True
431
log.debug("DBUS configuration reload possible? %s" % self.reload_dbus)
433
status, self.sys_uname_info = self.run('uname -a')
434
self.sys_uname_info = self.sys_uname_info.replace('\n', '')
435
log.debug(self.sys_uname_info)
437
# Record the installation time/date and version.
438
# Also has the effect of making the .hplip.conf file user r/w
439
# on the 1st run so that running hp-setup as root doesn't lock
440
# the user out of owning the file
441
user_conf.set('installation', 'date_time', time.strftime("%x %H:%M:%S", time.localtime()))
442
user_conf.set('installation', 'version', self.version_public)
444
if callback is not None:
448
def init_for_docs(self, distro_name, version, bitness=32):
449
self.distro_name = distro_name
450
self.distro_version = version
453
self.distro = self.distros[distro_name]['index']
455
log.error("Invalid distro name: %s" % distro_name)
458
self.bitness = bitness
460
for d in self.dependencies:
461
self.have_dependencies[d] = True
463
self.enable_ppds = self.get_distro_ver_data('ppd_install', 'ppd') == 'ppd'
464
self.ppd_dir = self.get_distro_ver_data('ppd_dir')
465
self.drv_dir = self.get_distro_ver_data('drv_dir')
467
self.distro_version_supported = True # for manual installs
470
def check_dependencies(self, callback=None):
473
for d in self.dependencies:
476
log.debug("Checking for dependency '%s'...\n" % d)
478
if callback is not None:
479
callback("Checking: %s\n" % d)
481
self.have_dependencies[d] = self.dependencies[d][3]()
482
log.debug("have %s = %s" % (d, self.have_dependencies[d]))
487
def password_func(self):
490
elif self.ui_mode == INTERACTIVE_MODE:
492
return getpass.getpass("Enter password: ")
497
def run(self, cmd, callback=None, timeout=300): # ==> status, output
500
output = cStringIO.StringIO()
503
check_timeout = not (cmd.startswith('xterm') or cmd.startswith('gnome-terminal'))
506
child = pexpect.spawn(cmd, timeout=1)
507
except pexpect.ExceptionPexpect:
517
i = child.expect_list(EXPECT_LIST)
527
if callback is not None:
528
if callback(cb): # cancel
533
span = int(time.time()-start)
537
log.debug("No output seen in %d secs" % span)
540
log.error("No output seen in over %d sec... (Is the CD-ROM/DVD source repository enabled? It shouldn't be!)" % timeout)
542
child.terminate(force=True)
546
ok, ret = True, output.getvalue()
549
elif i == 1: # TIMEOUT
552
elif i == 2: # zypper "Continue?"
553
child.sendline("YES")
556
child.sendline(self.password)
558
except (Exception, pexpect.ExceptionPexpect):
570
return child.exitstatus, ret
575
def get_distro(self):
576
log.debug("Determining distro...")
577
self.distro, self.distro_version = DISTRO_UNKNOWN, '0.0'
581
lsb_release = utils.which("lsb_release")
584
log.debug("Using 'lsb_release -is/-rs'")
585
cmd = os.path.join(lsb_release, "lsb_release")
586
status, name = self.run(cmd + ' -is')
587
name = name.lower().strip()
588
log.debug("Distro name=%s" % name)
590
if not status and name:
591
status, ver = self.run(cmd + ' -rs')
592
ver = ver.lower().strip()
593
log.debug("Distro version=%s" % ver)
595
if not status and ver:
596
for d in self.distros:
597
if name.find(d) > -1:
598
self.distro = self.distros[d]['index']
600
self.distro_version = ver
605
name = file('/etc/issue', 'r').read().lower().strip()
607
# Some O/Ss don't have /etc/issue (Mac)
608
self.distro, self.distro_version = DISTRO_UNKNOWN, '0.0'
610
for d in self.distros:
611
if name.find(d) > -1:
612
self.distro = self.distros[d]['index']
615
for x in self.distros[d].get('alt_names', ''):
616
if x and name.find(x) > -1:
617
self.distro = self.distros[d]['index']
625
for n in name.split():
628
m = '.'.join(n.split('.')[:2])
636
self.distro_version = '0.0'
638
self.distro_version = m
641
self.distro_version = m
644
log.debug("/etc/issue: %s %s" % (name, self.distro_version))
646
log.debug("distro=%d, distro_version=%s" % (self.distro, self.distro_version))
649
def distro_changed(self):
650
ppd_install = self.get_distro_ver_data('ppd_install', 'ppd')
652
if ppd_install not in ('ppd', 'drv'):
653
log.warning("Invalid ppd_install value: %s" % ppd_install)
655
self.enable_ppds = (ppd_install == 'ppd')
657
log.debug("Enable PPD install: %s (False=drv)" % self.enable_ppds)
659
self.ppd_dir = self.get_distro_ver_data('ppd_dir')
661
self.drv_dir = self.get_distro_ver_data('drv_dir')
662
if not self.enable_ppds and not self.drv_dir:
663
log.warning("Invalid drv_dir value: %s" % self.drv_dir)
665
self.distro_version_supported = self.get_distro_ver_data('supported', False)
666
self.selected_options['fax'] = self.get_distro_ver_data('fax_supported', True)
667
self.selected_options['network'] = self.get_distro_ver_data('network_supported', True)
668
self.selected_options['scan'] = self.get_distro_ver_data('scan_supported', True)
669
self.selected_options['policykit'] = self.get_distro_ver_data('policykit', False)
670
self.native_cups = self.get_distro_ver_data('native_cups', False)
672
# Adjust required flag based on the distro ver ui_toolkit value
673
ui_toolkit = self.get_distro_ver_data('ui_toolkit', 'qt4').lower()
675
if ui_toolkit == 'qt4':
676
log.debug("Default UI toolkit: Qt4")
677
self.ui_toolkit = 'qt4'
678
self.selected_options['gui_qt4'] = True
682
self.selected_options['gui_qt4'] = False
684
# Override with --qt4 command args
685
if self.enable is not None:
686
if 'qt4' in self.enable:
687
log.debug("User selected UI toolkit: Qt4")
688
self.ui_toolkit = 'qt4'
689
self.selected_options['gui_qt4'] = True
691
if self.disable is not None:
692
if 'qt4' in self.disable:
693
log.debug("User deselected UI toolkit: Qt4")
694
self.selected_options['gui_qt4'] = False
697
def __fixup_data(self, key, data):
698
field_type = self.FIELD_TYPES.get(key, TYPE_STRING)
699
#log.debug("%s (%s) %d" % (key, data, field_type))
701
if field_type == TYPE_BOOL:
702
return utils.to_bool(data)
704
elif field_type == TYPE_STRING:
705
if type('') == type(data):
710
elif field_type == TYPE_INT:
716
elif field_type == TYPE_LIST:
717
return [x for x in data.split(',') if x]
720
def load_distros(self):
721
if self.mode == MODE_INSTALLER:
722
distros_dat_file = os.path.join('installer', 'distros.dat')
724
elif self.mode == MODE_CREATE_DOCS:
725
distros_dat_file = os.path.join('..', '..', 'installer', 'distros.dat')
728
distros_dat_file = os.path.join(prop.home_dir, 'installer', 'distros.dat')
730
if not os.path.exists(distros_dat_file):
731
log.debug("DAT file not found at %s. Using local relative path..." % distros_dat_file)
732
distros_dat_file = os.path.join('installer', 'distros.dat')
734
distros_dat = ConfigBase(distros_dat_file)
735
distros_list = self.__fixup_data('distros', distros_dat.get('distros', 'distros'))
736
log.debug(distros_list)
738
for distro in distros_list:
742
if not distros_dat.has_section(distro):
743
log.debug("Missing distro section in distros.dat: [%s]" % distro)
746
for key in distros_dat.keys(distro):
747
d[key] = self.__fixup_data(key, distros_dat.get(distro, key))
749
self.distros[distro] = d
750
versions = self.__fixup_data("versions", distros_dat.get(distro, 'versions'))
751
self.distros[distro]['versions'] = {}
754
same_as_version, supported = False, True
756
ver_section = "%s:%s" % (distro, ver)
758
if not distros_dat.has_section(ver_section):
759
log.error("Missing version section in distros.dat: [%s:%s]" % (distro, ver))
762
if 'same_as_version' in distros_dat.keys(ver_section):
763
same_as_version = True
765
supported = self.__fixup_data('supported', distros_dat.get(ver_section, 'supported'))
767
for key in distros_dat.keys(ver_section):
768
v[key] = self.__fixup_data(key, distros_dat.get(ver_section, key))
770
self.distros[distro]['versions'][ver] = v
771
self.distros[distro]['versions'][ver]['dependency_cmds'] = {}
773
if same_as_version: # or not supported:
776
for dep in self.dependencies:
778
dep_section = "%s:%s:%s" % (distro, ver, dep)
780
if not distros_dat.has_section(dep_section) and not same_as_version:
781
log.debug("Missing dependency section in distros.dat: [%s:%s:%s]" % (distro, ver, dep))
787
for key in distros_dat.keys(dep_section):
788
dd[key] = self.__fixup_data(key, distros_dat.get(dep_section, key))
790
self.distros[distro]['versions'][ver]['dependency_cmds'][dep] = dd
792
versions = self.distros[distro]['versions']
794
ver_section = "%s:%s" % (distro, ver)
796
if 'same_as_version' in distros_dat.keys(ver_section):
797
v = self.__fixup_data("same_as_version", distros_dat.get(ver_section, 'same_as_version'))
798
log.debug("Setting %s:%s to %s:%s" % (distro, ver, distro, v))
801
vv = self.distros[distro]['versions'][v].copy()
802
vv['same_as_version'] = v
803
self.distros[distro]['versions'][ver] = vv
805
log.debug("Missing 'same_as_version=' version in distros.dat for section [%s:%s]." % (distro, v))
809
#pprint.pprint(self.distros)
811
def pre_install(self):
815
def pre_depend(self):
819
def check_python2x(self):
820
py_ver = sys.version_info
821
py_major_ver, py_minor_ver = py_ver[:2]
822
log.debug("Python ver=%d.%d" % (py_major_ver, py_minor_ver))
823
return py_major_ver >= 2
827
return check_tool('gcc --version', 0) and check_tool('g++ --version', 0)
830
def check_make(self):
831
return check_tool('make --version', 3.0)
834
def check_libusb(self):
835
if not check_lib('libusb'):
838
return len(locate_file_contains("usb.h", '/usr/include', 'usb_init(void)'))
841
def check_libjpeg(self):
842
return check_lib("libjpeg") and check_file("jpeglib.h")
845
def check_libcrypto(self):
846
return check_lib("libcrypto") and check_file("crypto.h")
849
def check_libpthread(self):
850
return check_lib("libpthread") and check_file("pthread.h")
853
def check_libnetsnmp(self):
854
return check_lib("libnetsnmp") and check_file("net-snmp-config.h")
857
def check_reportlab(self):
859
log.debug("Trying to import 'reportlab'...")
862
ver = reportlab.Version
866
log.debug("Can't determine version.")
869
log.debug("Version: %.1f" % ver_f)
871
log.debug("Success.")
881
def check_python23(self):
882
py_ver = sys.version_info
883
py_major_ver, py_minor_ver = py_ver[:2]
884
log.debug("Python ver=%d.%d" % (py_major_ver, py_minor_ver))
885
return py_major_ver >= 2 and py_minor_ver >= 3
888
def check_python_xml(self):
890
import xml.parsers.expat
897
def check_sane(self):
898
return check_lib('libsane')
901
def check_sane_devel(self):
902
return len(locate_file_contains("sane.h", '/usr/include', 'extern SANE_Status sane_init'))
905
def check_xsane(self):
906
if os.getenv('DISPLAY'):
907
return check_tool('xsane --version', 0.9) # will fail if X not running...
909
return bool(utils.which("xsane")) # ...so just see if it installed somewhere
912
def check_scanimage(self):
913
return check_tool('scanimage --version', 1.0)
917
return check_tool('gs -v', 7.05)
920
def check_pyqt4(self):
921
if self.ui_toolkit == 'qt4':
933
def check_pyqt4_dbus(self):
934
if self.ui_toolkit == 'qt4':
936
from dbus.mainloop.qt import DBusQtMainLoop
945
def check_python_devel(self):
946
return check_file('Python.h')
949
def check_pynotify(self):
958
def check_python_dbus(self):
959
log.debug("Checking for python-dbus (>= 0.80)...")
964
log.debug("Version: %s" % '.'.join([str(x) for x in dbus.version]))
965
return ver >= (0,80,0)
967
except AttributeError:
969
ver = dbus.__version__
970
log.debug("Version: %s" % dbus.__version__)
971
log.debug("HPLIP requires dbus version > 0.80.")
974
except AttributeError:
975
log.debug("Unknown version. HPLIP requires dbus version > 0.80.")
982
def check_python_ctypes(self):
990
def check_dbus(self):
991
log.debug("Checking for dbus running and header files present (dbus-devel)...")
992
return check_ps(['dbus-daemon']) and \
993
len(locate_file_contains("dbus-message.h", '/usr/include', 'dbus_message_new_signal'))
996
def check_cups_devel(self):
997
return check_file('cups.h') and bool(utils.which('lpr'))
1000
def check_cups(self):
1001
status, output = self.run('lpstat -r')
1003
log.debug("CUPS is not running.")
1006
log.debug("CUPS is running.")
1010
def check_cups_image(self):
1011
return check_file("raster.h", "/usr/include/cups")
1014
def check_hplip(self):
1015
log.debug("Checking for HPLIP...")
1016
return locate_files('hplip.conf', '/etc/hp')
1019
def check_hpssd(self):
1020
log.debug("Checking for hpssd...")
1021
return check_ps(['hpssd'])
1024
def check_libtool(self):
1025
log.debug("Checking for libtool...")
1026
return check_tool('libtool --version')
1029
def check_pil(self):
1030
log.debug("Checking for PIL...")
1038
def check_cupsddk(self):
1039
log.debug("Checking for cups-ddk...")
1040
# TODO: Compute these paths some way or another...
1041
#return check_tool("/usr/lib/cups/driver/drv list") and os.path.exists("/usr/share/cupsddk/include/media.defs")
1042
return (check_file('drv', "/usr/lib/cups/driver") or check_file('drv', "/usr/lib64/cups/driver")) and \
1043
check_file('media.defs', "/usr/share/cupsddk/include")
1046
def check_policykit(self):
1047
log.debug("Checking for PolicyKit...")
1048
return (check_file('PolicyKit.conf', "/etc/PolicyKit") and check_file('org.gnome.PolicyKit.AuthorizationManager.service', "/usr/share/dbus-1/services")) or (check_file('50-localauthority.conf', "/etc/polkit-1/localauthority.conf.d") and check_file('org.freedesktop.PolicyKit1.service', "/usr/share/dbus-1/system-services"))
1050
def check_pkg_mgr(self):
1052
Check if any pkg mgr processes are running
1054
log.debug("Searching for '%s' in running processes..." % self.package_mgrs)
1056
processes = get_process_list()
1058
for pid, cmdline in processes:
1059
for p in self.package_mgrs:
1061
for k in OK_PROCESS_LIST:
1067
log.debug("Found: %s (%d)" % (cmdline, pid))
1068
return (pid, cmdline)
1070
log.debug("Not found")
1074
def get_hplip_version(self):
1075
self.version_description, self.version_public, self.version_internal = '', '', ''
1077
if self.mode == MODE_INSTALLER:
1078
ac_init_pat = re.compile(r"""AC_INIT\(\[(.*?)\], *\[(.*?)\], *\[(.*?)\], *\[(.*?)\] *\)""", re.IGNORECASE)
1081
config_in = open('./configure.in', 'r')
1083
self.version_description, self.version_public, self.version_internal = \
1084
'', sys_conf.get('configure', 'internal-tag', '0.0.0'), prop.installed_version
1087
if c.startswith("AC_INIT"):
1088
match_obj = ac_init_pat.search(c)
1089
self.version_description = match_obj.group(1)
1090
self.version_public = match_obj.group(2)
1091
self.version_internal = match_obj.group(3)
1092
name = match_obj.group(4)
1098
log.error("Invalid archive!")
1103
self.version_description, self.version_public, self.version_internal = \
1104
'', sys_conf.get('configure', 'internal-tag', '0.0.0'), prop.installed_version
1106
self.version_description, self.version_public, self.version_internal = '', '', ''
1108
return self.version_description, self.version_public, self.version_internal
1111
def configure(self):
1112
configure_cmd = './configure'
1114
dbus_avail = self.have_dependencies['dbus'] and self.have_dependencies['python-dbus']
1115
configuration['network-build'] = self.selected_options['network']
1116
configuration['fax-build'] = self.selected_options['fax'] and dbus_avail
1117
configuration['dbus-build'] = dbus_avail
1118
configuration['qt4'] = self.selected_options['gui_qt4']
1119
configuration['scan-build'] = self.selected_options['scan']
1120
configuration['doc-build'] = self.selected_options['docs']
1121
configuration['policykit'] = self.selected_options['policykit']
1123
# Setup printer driver configure flags based on distro data...
1124
if self.native_cups: # hpcups
1125
configuration['hpcups-install'] = True
1126
configuration['hpijs-install'] = False
1127
configuration['foomatic-ppd-install'] = False
1128
configuration['foomatic-drv-install'] = False
1130
if self.enable_ppds:
1131
configuration['cups-ppd-install'] = True
1132
configuration['cups-drv-install'] = False
1134
configuration['cups-ppd-install'] = False
1135
configuration['cups-drv-install'] = True
1137
else: # HPIJS/foomatic
1138
configuration['hpcups-install'] = False
1139
configuration['hpijs-install'] = True
1140
configuration['cups-ppd-install'] = False
1141
configuration['cups-drv-install'] = False
1143
if self.enable_ppds:
1144
configuration['foomatic-ppd-install'] = True
1145
configuration['foomatic-drv-install'] = False
1147
configuration['foomatic-ppd-install'] = False
1148
configuration['foomatic-drv-install'] = True
1151
# ... and then override and adjust for consistency with passed in parameters
1152
if self.enable is not None:
1153
for c in self.enable:
1154
if c == 'hpcups-install':
1155
configuration['hpijs-install'] = False
1156
configuration['foomatic-ppd-install'] = False
1157
configuration['foomatic-drv-install'] = False
1158
elif c == 'hpijs-install':
1159
configuration['hpcups-install'] = False
1160
configuration['cups-ppd-install'] = False
1161
configuration['cups-drv-install'] = False
1162
elif c == 'foomatic-ppd-install':
1163
configuration['foomatic-drv-install'] = False
1164
elif c == 'foomatic-drv-install':
1165
configuration['foomatic-ppd-install'] = False
1166
elif c == 'cups-ppd-install':
1167
configuration['cups-drv-install'] = False
1168
elif c == 'cups-drv-install':
1169
configuration['cups-ppd-install'] = False
1171
if self.disable is not None:
1172
for c in self.disable:
1173
if c == 'hpcups-install':
1174
configuration['hpijs-install'] = True
1175
configuration['cups-ppd-install'] = False
1176
configuration['cups-drv-install'] = False
1177
elif c == 'hpijs-install':
1178
configuration['hpcups-install'] = True
1179
configuration['foomatic-ppd-install'] = False
1180
configuration['foomatic-drv-install'] = False
1181
elif c == 'foomatic-ppd-install':
1182
configuration['foomatic-drv-install'] = True
1183
elif c == 'foomatic-drv-install':
1184
configuration['foomatic-ppd-install'] = True
1185
elif c == 'cups-ppd-install':
1186
configuration['cups-drv-install'] = True
1187
elif c == 'cups-drv-install':
1188
configuration['cups-ppd-install'] = True
1190
if self.ppd_dir is not None:
1191
configure_cmd += ' --with-hpppddir=%s' % self.ppd_dir
1193
libdir_path = self.get_distro_ver_data('libdir_path',False)
1194
if libdir_path and self.bitness == 64:
1195
configure_cmd += ' --libdir=%s' % (libdir_path)
1196
elif self.bitness == 64:
1197
configure_cmd += ' --libdir=/usr/lib64'
1199
configure_cmd += ' --prefix=%s' % self.install_location
1201
if self.get_distro_ver_data('cups_path_with_bitness', False) and self.bitness == 64:
1202
configure_cmd += ' --with-cupsbackenddir=/usr/lib64/cups/backend --with-cupsfilterdir=/usr/lib64/cups/filter'
1204
if self.get_distro_ver_data('acl_rules', False):
1205
configure_cmd += ' --enable-udev-acl-rules'
1207
if self.enable is not None:
1208
for c in self.enable:
1209
configuration[c] = True
1211
if self.disable is not None:
1212
for c in self.disable:
1213
configuration[c] = False
1215
for c in configuration:
1216
if configuration[c]:
1217
configure_cmd += ' --enable-%s' % c
1219
configure_cmd += ' --disable-%s' % c
1221
return configure_cmd
1223
def configure_html(self):
1224
configure_cmd = './configure'
1225
configure_cmd += ' --prefix=/usr'
1226
configure_cmd += ' --with-hpppddir=%s' % self.ppd_dir
1228
if self.bitness == 64:
1229
configure_cmd += ' --libdir=/usr/lib64'
1231
self.ui_toolkit = self.get_distro_ver_data('ui_toolkit')
1232
if self.ui_toolkit is not None and self.ui_toolkit == 'qt3':
1233
configure_cmd += ' --enable-qt3 --disable-qt4'
1235
configure_cmd += ' --enable-qt4'
1237
self.native_cups = self.get_distro_ver_data('native_cups')
1238
if self.native_cups is not None and self.native_cups == 1:
1239
configure_cmd += ' --enable-hpcups-install --enable-cups-drv-install --enable-cups-ppd-install --disable-hpijs-install --disable-foomatic-drv-install --disable-foomatic-ppd-install --disable-foomatic-rip-hplip-install'
1241
configure_cmd += ' --disable-hpcups-install --disable-cups-drv-install --disable-cups-ppd-install --enable-hpijs-install --enable-foomatic-drv-install --enable-foomatic-ppd-install --enable-foomatic-rip-hplip-install'
1243
self.fax_supported = self.get_distro_ver_data('fax_supported')
1244
if self.fax_supported is None:
1245
configure_cmd += ' --disable-fax-build --disable-dbus-build'
1247
configure_cmd += ' --enable-fax-build --enable-dbus-build'
1249
self.network_supported = self.get_distro_ver_data('network_supported')
1250
if self.network_supported is None:
1251
configure_cmd += ' --disable-network-build'
1253
configure_cmd += ' --enable-network-build'
1255
self.scan_supported = self.get_distro_ver_data('scan_supported')
1256
if self.scan_supported is None:
1257
configure_cmd += ' --disable-scan-build'
1259
configure_cmd += ' --enable-scan-build'
1261
self.policykit = self.get_distro_ver_data('policykit')
1262
if self.policykit is not None and self.policykit == 1:
1263
configure_cmd += ' --enable-policykit'
1265
configure_cmd += ' --disable-policykit'
1267
return configure_cmd
1269
def configure_qt4(self):
1270
configure_cmd = './configure'
1271
configure_cmd += ' --prefix=/usr'
1272
configure_cmd += ' --with-hpppddir=%s' % self.ppd_dir
1274
if self.bitness == 64:
1275
configure_cmd += ' --libdir=/usr/lib64'
1277
self.ui_toolkit = self.get_distro_ver_data('ui_toolkit')
1278
if self.ui_toolkit is not None and self.ui_toolkit == 'qt3':
1279
configure_cmd += ' --enable-qt3 --disable-qt4'
1281
configure_cmd += ' --enable-qt4'
1283
self.native_cups = self.get_distro_ver_data('native_cups')
1284
self.ppd_install = self.get_distro_ver_data('ppd_install')
1285
if self.native_cups is not None and self.native_cups == 1:
1286
configure_cmd += ' --enable-hpcups-install'
1287
if self.ppd_install == 'drv':
1288
configure_cmd += ' --enable-cups-drv-install --disable-cups-ppd-install'
1290
configure_cmd += ' --enable-cups-ppd-install --disable-cups-drv-install'
1291
configure_cmd += ' --disable-hpijs-install --disable-foomatic-drv-install --disable-foomatic-ppd-install --disable-foomatic-rip-hplip-install'
1293
configure_cmd += ' --enable-hpijs-install'
1294
if self.ppd_install == 'drv':
1295
configure_cmd += ' --enable-foomatic-drv-install --disable-foomatic-ppd-install'
1297
configure_cmd += ' --enable-foomatic-ppd-install --disable-foomatic-drv-install'
1298
configure_cmd += ' --enable-foomatic-rip-hplip-install --disable-hpcups-install --disable-cups-drv-install --disable-cups-ppd-install'
1300
self.fax_supported = self.get_distro_ver_data('fax_supported')
1301
if self.fax_supported is None:
1302
configure_cmd += ' --disable-fax-build --disable-dbus-build'
1304
configure_cmd += ' --enable-fax-build --enable-dbus-build'
1306
self.network_supported = self.get_distro_ver_data('network_supported')
1307
if self.network_supported is None:
1308
configure_cmd += ' --disable-network-build'
1310
configure_cmd += ' --enable-network-build'
1312
self.scan_supported = self.get_distro_ver_data('scan_supported')
1313
if self.scan_supported is None:
1314
configure_cmd += ' --disable-scan-build'
1316
configure_cmd += ' --enable-scan-build'
1318
self.policykit = self.get_distro_ver_data('policykit')
1319
if self.policykit is not None and self.policykit == 1:
1320
configure_cmd += ' --enable-policykit'
1322
configure_cmd += ' --disable-policykit'
1324
return configure_cmd
1327
def restart_cups(self):
1328
if os.path.exists('/etc/init.d/cups'):
1329
cmd = self.su_sudo() % '/etc/init.d/cups restart'
1331
elif os.path.exists('/etc/init.d/cupsys'):
1332
cmd = self.su_sudo() % '/etc/init.d/cupsys restart'
1335
cmd = self.su_sudo() % 'killall -HUP cupsd'
1340
def stop_hplip(self):
1341
return self.su_sudo() % "/etc/init.d/hplip stop"
1345
if os.geteuid() == 0:
1349
cmd = self.distros[self.distro_name]['su_sudo']
1358
def su_sudo_str(self):
1359
return self.get_distro_data('su_sudo', 'su')
1362
def build_cmds(self):
1363
return [self.configure(),
1366
self.su_sudo() % 'make install']
1369
def get_distro_ver_data(self, key, default=None):
1371
return self.distros[self.distro_name]['versions'][self.distro_version].get(key, None) or \
1372
self.distros[self.distro_name].get(key, None) or default
1379
def get_distro_data(self, key, default=None):
1381
return self.distros[self.distro_name].get(key, None) or default
1386
def get_ver_data(self, key, default=None):
1388
return self.distros[self.distro_name]['versions'][self.distro_version].get(key, None) or default
1395
def get_dependency_data(self, dependency):
1396
dependency_cmds = self.get_ver_data("dependency_cmds", {})
1397
dependency_data = dependency_cmds.get(dependency, {})
1398
packages = dependency_data.get('packages', [])
1399
commands = dependency_data.get('commands', [])
1400
return packages, commands
1403
def get_dependency_commands(self):
1404
dd = self.dependencies.keys()
1406
commands_to_run = []
1407
packages_to_install = []
1408
overall_commands_to_run = []
1411
for opt in self.dependencies[d][1]:
1412
if self.selected_options[opt]:
1415
pkgs, cmds = self.get_dependency_data(d)
1419
if not p in packages_to_install:
1420
packages_to_install.append(p)
1423
commands_to_run.extend(cmds)
1425
package_mgr_cmd = self.get_distro_data('package_mgr_cmd')
1427
overall_commands_to_run.extend(commands_to_run)
1430
packages_to_install = ' '.join(packages_to_install)
1431
overall_commands_to_run.append(utils.cat(package_mgr_cmd))
1433
if not overall_commands_to_run:
1434
log.error("No cmds/pkgs")
1436
return overall_commands_to_run
1439
def distro_known(self):
1440
return self.distro != DISTRO_UNKNOWN and self.distro_version != DISTRO_VER_UNKNOWN
1443
def distro_supported(self):
1444
if self.mode == MODE_INSTALLER:
1445
return self.distro != DISTRO_UNKNOWN and self.distro_version != DISTRO_VER_UNKNOWN and self.get_ver_data('supported', False)
1447
return True # For docs (manual install)
1450
def sort_vers(self, x, y):
1452
return cmp(float(x), float(y))
1457
def running_as_root(self):
1458
return os.geteuid() == 0
1461
def show_release_notes_in_browser(self):
1462
url = "file://%s" % os.path.join(os.getcwd(), 'doc', 'release_notes.html')
1464
status, output = self.run("xhost +")
1468
def count_num_required_missing_dependencies(self):
1470
for d, desc, opt in self.missing_required_dependencies():
1471
num_req_missing += 1
1472
return num_req_missing
1475
def count_num_optional_missing_dependencies(self):
1477
for d, desc, req, opt in self.missing_optional_dependencies():
1478
num_opt_missing += 1
1479
return num_opt_missing
1482
def missing_required_dependencies(self): # missing req. deps in req. options
1483
for opt in self.components[self.selected_component][1]:
1484
if self.options[opt][0]: # required options
1485
for d in self.options[opt][2]: # dependencies for option
1486
if self.dependencies[d][0]: # required option
1487
if not self.have_dependencies[d]: # missing
1488
log.debug("Missing required dependency: %s" % d)
1489
yield d, self.dependencies[d][2], opt
1490
# depend, desc, option
1492
def missing_optional_dependencies(self):
1493
# missing deps in opt. options
1494
for opt in self.components[self.selected_component][1]:
1495
if not self.options[opt][0]: # not required option
1496
if self.selected_options[opt]: # only for options that are ON
1497
for d in self.options[opt][2]: # dependencies
1498
if not self.have_dependencies[d]: # missing dependency
1499
log.debug("Missing optional dependency: %s" % d)
1500
yield d, self.dependencies[d][2], self.dependencies[d][0], opt
1501
# depend, desc, required_for_opt, opt
1503
# opt. deps in req. options
1504
for opt in self.components[self.selected_component][1]:
1505
if self.options[opt][0]: # required options
1506
for d in self.options[opt][2]: # dependencies for option
1508
status, output = self.run('cups-config --version')
1510
if status == 0 and (string.count(output, '.') == 1 or string.count(output, '.') == 2):
1511
if string.count(output, '.') == 1:
1512
major, minor = string.split(output, '.', 2)
1513
if string.count(output, '.') == 2:
1514
major, minor, release = string.split(output, '.', 3)
1515
if len(minor) > 1 and minor[1] >= '0' and minor[1] <= '9':
1516
minor = ((ord(minor[0]) - ord('0')) * 10) + (ord(minor[1]) - ord('0'))
1518
minor = ord(minor[0]) - ord('0')
1519
if major > '1' or (major == '1' and minor >= 4):
1521
if not self.dependencies[d][0]: # optional dep
1522
if not self.have_dependencies[d]: # missing
1523
log.debug("Missing optional dependency: %s" % d)
1524
yield d, self.dependencies[d][2], self.dependencies[d][0], opt
1525
# depend, desc, option
1527
def select_options(self, answer_callback):
1529
# not-required options
1530
for opt in self.components[self.selected_component][1]:
1531
if not self.options[opt][0]: # not required
1534
if not self.selected_options[opt]:
1537
self.selected_options[opt] = answer_callback(opt, self.options[opt][1], default)
1539
if self.selected_options[opt]: # only for options that are ON
1540
for d in self.options[opt][2]: # dependencies
1541
if not self.have_dependencies[d]: # missing dependency
1542
log.debug("Missing optional dependency: %s" % d)
1543
num_opt_missing += 1
1545
return num_opt_missing
1548
def check_network_connection(self):
1549
self.network_connected = False
1551
wget = utils.which("wget")
1553
wget = os.path.join(wget, "wget")
1554
cmd = "%s --timeout=60 --output-document=- %s" % (wget, HTTP_GET_TARGET)
1556
status, output = self.run(cmd)
1557
log.debug("wget returned: %d" % status)
1558
self.network_connected = (status == 0)
1561
curl = utils.which("curl")
1563
curl = os.path.join(curl, "curl")
1564
cmd = "%s --output - --connect-timeout 5 --max-time 10 %s" % (curl, HTTP_GET_TARGET)
1566
status, output = self.run(cmd)
1567
log.debug("curl returned: %d" % status)
1568
self.network_connected = (status == 0)
1571
ping = utils.which("ping")
1574
ping = os.path.join(ping, "ping")
1575
cmd = "%s -c1 -W1 -w10 %s" % (ping, PING_TARGET)
1577
status, output = self.run(cmd)
1578
log.debug("ping returned: %d" % status)
1579
self.network_connected = (status == 0)
1581
return self.network_connected
1584
def run_pre_install(self, callback=None):
1585
pre_cmd = self.get_distro_ver_data('pre_install_cmd')
1590
status, output = self.run(cmd)
1593
log.warn("An error occurred running '%s'" % cmd)
1595
if callback is not None:
1596
callback(cmd, "Pre-install step %d" % x)
1606
def run_pre_depend(self, callback=None):
1607
pre_cmd = self.get_distro_ver_data('pre_depend_cmd')
1612
status, output = self.run(cmd)
1615
log.warn("An error occurred running '%s'" % cmd)
1617
if callback is not None:
1618
callback(cmd, "Pre-depend step %d" % x)
1623
def run_post_depend(self, callback=None):
1624
post_cmd = self.get_distro_ver_data('post_depend_cmd')
1628
for cmd in post_cmd:
1629
status, output = self.run(cmd)
1632
log.warn("An error occurred running '%s'" % cmd)
1634
if callback is not None:
1635
callback(cmd, "Post-depend step %d" % x)
1640
def run_open_mdns_port(self, callback=None):
1641
open_mdns_port_cmd = self.get_distro_ver_data('open_mdns_port')
1642
log.debug(open_mdns_port_cmd)
1643
if open_mdns_port_cmd:
1645
for cmd in open_mdns_port_cmd:
1646
cmd = self.su_sudo() % cmd
1647
status, output = self.run(cmd)
1650
log.warn("An error occurred running '%s'" % cmd)
1653
if callback is not None:
1654
callback(cmd, "Open mDNS/Bonjour step %d" % x)
1659
def pre_build(self):
1661
if self.get_distro_ver_data('fix_ppd_symlink', False):
1662
cmds.append(self.su_sudo() % 'python ./installer/fix_symlink.py')
1667
def run_pre_build(self, callback=None):
1669
for cmd in self.pre_build():
1670
status, output = self.run(cmd)
1671
if callback is not None:
1672
callback(cmd, "Pre-build step %d" % x)
1677
def run_post_build(self, callback=None):
1679
for cmd in self.post_build():
1680
status, output = self.run(cmd)
1681
if callback is not None:
1682
callback(cmd, "Post-build step %d" % x)
1687
def post_build(self):
1689
# Reload DBUS configuration if distro supports it and PolicyKit
1691
if self.reload_dbus and self.selected_options['policykit']:
1692
cmds.append(self.su_sudo() % "sh /etc/init.d/dbus reload")
1693
log.debug("Will reload DBUS configuration for PolicyKit support")
1695
# Kill any running hpssd.py instance from a previous install
1696
if self.check_hpssd():
1697
pid = get_ps_pid('hpssd')
1699
kill = os.path.join(utils.which("kill"), "kill") + " %d" % pid
1700
cmds.append(self.su_sudo() % kill)
1702
# Add user to group if needed
1703
# add_user_to_group=<usermod params> [TYPE_STRING] (leave empty for none) [ex. "-a -G sys" or "-G lp"]
1704
add_user_to_group = self.get_distro_ver_data('add_user_to_group', '')
1705
if add_user_to_group:
1706
usermod = os.path.join(utils.which("usermod"), "usermod") + " %s %s" % (add_user_to_group, prop.username)
1707
cmds.append(self.su_sudo() % usermod)
1714
pkill = utils.which('pkill')
1716
cmd = "%s -KILL -u %s" % (os.path.join(pkill, "pkill"), prop.username)
1717
cmd = self.su_sudo() % cmd
1718
status, output = self.run(cmd)
1727
shutdown = utils.which('shutdown')
1729
cmd = "%s -r now" % (os.path.join(shutdown, "shutdown"))
1730
cmd = self.su_sudo() % cmd
1731
status, output = self.run(cmd)
1738
def run_hp_setup(self):
1740
hpsetup = utils.which("hp-setup")
1748
status, output = self.run(cmd)
1752
def remove_hplip(self, callback=None):
1754
self.stop_pre_2x_hplip(callback)
1756
hplip_remove_cmd = self.get_distro_data('hplip_remove_cmd')
1757
if hplip_remove_cmd:
1758
if callback is not None:
1759
callback(hplip_remove_cmd, "Removing old HPLIP version")
1761
status, output = self.run(hplip_remove_cmd)
1764
self.hplip_present = self.check_hplip()
1766
if not self.hplip_present:
1772
def stop_pre_2x_hplip(self, callback=None):
1773
hplip_init_script = '/etc/init.d/hplip stop'
1774
if os.path.exists(hplip_init_script):
1775
cmd = self.su_sudo() % hplip_init_script
1777
if callback is not None:
1778
callback(cmd, "Stopping old HPLIP version.")
1780
status, output = self.run(cmd)
1784
def check_password(self, password_entry_callback, callback=None):
1785
self.clear_su_sudo_password()
1788
self.password = password_entry_callback()
1789
cmd = self.su_sudo() % "true"
1793
status, output = self.run(cmd)
1799
if callback is not None:
1800
callback("", "Password accepted")
1803
if callback is not None:
1804
if "not in the sudoers file" in output:
1805
callback("", "%s is not in the sudoers file. Check privileges\n" %(os.getenv('USER')) )
1808
callback("", "Password incorrect. %d attempt(s) left." % (3-x ))
1817
def clear_su_sudo_password(self):
1818
if self.su_sudo_str() == 'sudo':
1819
log.debug("Clearing password...")
1826
def set_plugin_version(self):
1827
self.plugin_version = prop.installed_version
1828
log.debug("Plug-in version=%s" % self.plugin_version)
1829
self.plugin_name = 'hplip-%s-plugin.run' % self.plugin_version
1830
log.debug("Plug-in=%s" % self.plugin_name)
1833
def get_plugin_conf_url(self):
1834
url = "http://hplip.sf.net/plugin.conf"
1835
home = sys_conf.get('dirs', 'home')
1837
if os.path.exists('/etc/hp/plugin.conf'):
1838
url = "file:///etc/hp/plugin.conf"
1840
elif os.path.exists(os.path.join(home, 'plugin.conf')):
1841
url = "file://" + os.path.join(home, 'plugin.conf')
1843
log.debug("Plugin.conf url: %s" % url)
1847
def get_plugin_info(self, plugin_conf_url, callback):
1848
ok, size, checksum, timestamp, url = False, 0, 0, 0.0, ''
1850
if not self.create_plugin_dir():
1851
log.error("Could not create plug-in directory.")
1852
return '', 0, 0, 0, False
1854
local_conf_fp, local_conf = utils.make_temp_file()
1856
#if os.path.exists(local_conf):
1857
#os.remove(local_conf)
1861
#filename, headers = urllib.urlretrieve(plugin_conf_url, local_conf, callback)
1862
wget = utils.which("wget")
1864
wget = os.path.join(wget, "wget")
1865
status, output = self.run("%s --timeout=60 --output-document=%s %s --cache=off" %(wget, local_conf, plugin_conf_url))
1867
log.error("Plugin download failed with error code = %d" %status)
1868
return '', 0, 0, 0, False
1870
log.error("Please install wget package to download the plugin.")
1871
return '', 0, 0, 0, False
1873
log.error("I/O Error: %s" % e.strerror)
1874
return '', 0, 0, 0, False
1876
if not os.path.exists(local_conf):
1877
log.error("plugin.conf not found.")
1878
return '', 0, 0, 0, False
1880
plugin_conf_p = ConfigParser.ConfigParser()
1883
plugin_conf_p.read(local_conf)
1884
except (ConfigParser.MissingSectionHeaderError, ConfigParser.ParsingError):
1885
log.error("Error parsing file - 404 error?")
1886
return '', 0, 0, 0, False
1889
url = plugin_conf_p.get(self.plugin_version, 'url')
1890
size = plugin_conf_p.getint(self.plugin_version, 'size')
1891
checksum = plugin_conf_p.get(self.plugin_version, 'checksum')
1892
timestamp = plugin_conf_p.getfloat(self.plugin_version, 'timestamp')
1894
except (KeyError, ConfigParser.NoSectionError):
1895
log.error("Error reading plugin.conf: Missing section [%s]" % self.plugin_version)
1896
return '', 0, 0, 0, False
1899
os.close(local_conf_fp)
1900
os.remove(local_conf)
1902
return url, size, checksum, timestamp, ok
1905
def create_plugin_dir(self):
1906
if not os.path.exists(self.plugin_path):
1908
log.debug("Creating plugin directory: %s" % self.plugin_path)
1910
os.makedirs(self.plugin_path, 0755)
1912
except (OSError, IOError), e:
1913
log.error("Unable to create directory: %s" % e.strerror)
1919
def isErrorPage(self, page):
1921
Example code from David Mertz' Text Processing in Python.
1922
Released in the Public Domain.
1926
for pat, prob in err_pats.items():
1927
if err_score > 0.9: break
1928
if re.search(pat, page):
1931
log.debug("File error page score: %f" % (err_score))
1933
return err_score > 0.50
1936
def download_plugin(self, url, size, checksum, timestamp, callback=None):
1937
log.debug("Downloading %s plug-in file from '%s' to '%s'..." % (self.plugin_version, url, self.plugin_path))
1939
if not self.create_plugin_dir():
1940
return PLUGIN_INSTALL_ERROR_DIRECTORY_ERROR, self.plugin_path
1942
plugin_file = os.path.join(self.plugin_path, self.plugin_name)
1945
#Check whether plugin is accessible in Openprinting.org website otherwise dowload plugin from alternate location.
1946
wget = utils.which("wget")
1948
wget = os.path.join(wget, "wget")
1949
cmd = "%s --cache=off -P %s %s" % (wget,self.plugin_path,url)
1951
status, output = self.run(cmd)
1952
log.debug("wget returned: %d" % status)
1955
if (status != 0) and 'file://' not in url:
1956
url = os.path.join(PLUGIN_FALLBACK_LOCATION, self.plugin_name)
1957
log.info("Plugin is not accessible. Trying to download it from fallback location: [%s]" % url)
1958
cmd = "%s --cache=off -P %s %s" % (wget,self.plugin_path,url)
1960
status, output = self.run(cmd)
1961
#filename, headers = urllib.urlretrieve(url, plugin_file, callback)
1963
log.error("Plug-in download failed: %s" % e.strerror)
1964
return PLUGIN_INSTALL_ERROR_PLUGIN_FILE_NOT_FOUND, e.strerror
1966
if self.isErrorPage(file(plugin_file, 'r').read(1024)):
1967
log.debug(file(plugin_file, 'r').read(1024))
1968
os.remove(plugin_file)
1969
return PLUGIN_INSTALL_ERROR_PLUGIN_FILE_NOT_FOUND, -1
1971
calc_checksum = get_checksum(file(plugin_file, 'r').read())
1972
log.debug("D/L file checksum=%s" % calc_checksum)
1974
# Try to download and check the GPG digital signature
1975
digsig_url = url + '.asc'
1976
digsig_file = plugin_file + '.asc'
1978
log.debug("Downloading %s plug-in digital signature file from '%s' to '%s'..." % (self.plugin_version, digsig_url, digsig_file))
1981
cmd = "%s --cache=off -P %s %s" % (wget,self.plugin_path,digsig_url)
1983
status, output = self.run(cmd)
1984
#filename, headers = urllib.urlretrieve(digsig_url, digsig_file, callback)
1986
log.error("Plug-in GPG file [%s] download failed: %s" % (digsig_url,e.strerror))
1987
return PLUGIN_INSTALL_ERROR_DIGITAL_SIG_NOT_FOUND, e.strerror
1989
if self.isErrorPage(file(digsig_file, 'r').read(1024)):
1990
log.debug(file(digsig_file, 'r').read())
1991
os.remove(digsig_file)
1992
return PLUGIN_INSTALL_ERROR_DIGITAL_SIG_NOT_FOUND, -1
1994
gpg = utils.which('gpg')
1996
gpg = os.path.join(gpg, 'gpg')
1997
cmd = '%s --no-permission-warning --keyserver pgp.mit.edu --recv-keys 0xA59047B9' % gpg
1998
log.info("Receiving digital keys: %s" % cmd)
1999
status, output = self.run(cmd)
2003
return PLUGIN_INSTALL_ERROR_UNABLE_TO_RECV_KEYS, status
2005
cmd = '%s --no-permission-warning --verify %s %s' % (gpg, digsig_file, plugin_file)
2006
log.debug("Verifying plugin with digital keys: %s" % cmd)
2007
status, output = self.run(cmd)
2009
log.debug("%s status: %d" % (gpg, status))
2012
return PLUGIN_INSTALL_ERROR_DIGITAL_SIG_BAD, status
2015
return PLUGIN_INSTALL_ERROR_NONE, plugin_file
2018
def check_for_plugin(self):
2020
is_installed = utils.to_bool(sys_state.get('plugin', 'installed', '0'))
2022
log.debug("plugin is installed")
2024
log.debug("plugin is not installed")
2028
def run_plugin(self, mode=GUI_MODE, callback=None):
2029
plugin_file = os.path.join(self.plugin_path, self.plugin_name)
2031
if not os.path.exists(plugin_file):
2034
if mode == GUI_MODE:
2035
return os.system("sh %s --nox11 -- -u" % plugin_file) == 0
2037
if os.system("sh %s --nox11 -- -i" % plugin_file) == 0:
2040
log.error("Python gobject/dbus may be not installed")
2044
def delete_plugin(self):
2045
plugin_file = os.path.join(self.plugin_path, self.plugin_name)
2046
digsig_file = plugin_file + ".asc"
2048
if os.path.exists(plugin_file):
2049
os.unlink(plugin_file)
2050
if os.path.exists(digsig_file):
2051
os.unlink(digsig_file)
1
# -*- coding: utf-8 -*-
3
# (c) Copyright 2003-2009 Hewlett-Packard Development Company, L.P.
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
35
import hashlib # new in 2.5
38
return hashlib.sha1(s).hexdigest()
41
import sha # deprecated in 2.6/3.0
44
return sha.new(s).hexdigest()
47
import urllib # TODO: Replace with urllib2 (urllib is deprecated in Python 3.0)
52
from base.codes import *
53
from base import utils, pexpect,tui
59
DISTRO_VER_UNKNOWN = '0.0'
61
MODE_INSTALLER = 0 # hplip-install/hp-setup
62
MODE_CHECK = 1 # hp-check
63
MODE_CREATE_DOCS = 2 # create_docs
70
DEPENDENCY_RUN_TIME = 1
71
DEPENDENCY_COMPILE_TIME = 2
72
DEPENDENCY_RUN_AND_COMPILE_TIME = 3
74
# Plug-in download errors
75
PLUGIN_INSTALL_ERROR_NONE = 0
76
PLUGIN_INSTALL_ERROR_PLUGIN_FILE_NOT_FOUND = 1
77
PLUGIN_INSTALL_ERROR_DIGITAL_SIG_NOT_FOUND = 2
78
PLUGIN_INSTALL_ERROR_DIGITAL_SIG_BAD = 3
79
PLUGIN_INSTALL_ERROR_PLUGIN_FILE_CHECKSUM_ERROR = 4
80
PLUGIN_INSTALL_ERROR_NO_NETWORK = 5
81
PLUGIN_INSTALL_ERROR_DIRECTORY_ERROR = 6
82
PLUGIN_INSTALL_ERROR_UNABLE_TO_RECV_KEYS = 7
85
#Plugin installation status values
86
PLUGIN_STATUS_PARTIAL_FILES_PRESENT = -1
87
PLUGIN_STATUS_FILES_NOT_PRESENT = 0
88
PLUGIN_STATUS_FILES_PRESENT = 1
91
PING_TARGET = "www.google.com"
92
HTTP_GET_TARGET = "http://www.google.com"
93
PLUGIN_FALLBACK_LOCATION = 'http://hplipopensource.com/hplip-web/plugin/'
98
"Continue?", # 2 (for zypper)
99
"passwor[dt]", # en/de/it/ru
104
"palavra passe", # pt
110
# Mapping from patterns to probability contribution of pattern
111
# Example code from David Mertz' Text Processing in Python.
112
# Released in the Public Domain.
113
err_pats = {r'(?is)<TITLE>.*?(404|403).*?ERROR.*?</TITLE>': 0.95,
114
r'(?is)<TITLE>.*?ERROR.*?(404|403).*?</TITLE>': 0.95,
115
r'(?is)<TITLE>ERROR</TITLE>': 0.30,
116
r'(?is)<TITLE>.*?ERROR.*?</TITLE>': 0.10,
117
r'(?is)<META .*?(404|403).*?ERROR.*?>': 0.80,
118
r'(?is)<META .*?ERROR.*?(404|403).*?>': 0.80,
119
r'(?is)<TITLE>.*?File Not Found.*?</TITLE>': 0.80,
120
r'(?is)<TITLE>.*?Not Found.*?</TITLE>': 0.40,
121
r'(?is)<BODY.*(404|403).*</BODY>': 0.10,
122
r'(?is)<H1>.*?(404|403).*?</H1>': 0.15,
123
r'(?is)<BODY.*not found.*</BODY>': 0.10,
124
r'(?is)<H1>.*?not found.*?</H1>': 0.15,
125
r'(?is)<BODY.*the requested URL.*</BODY>': 0.10,
126
r'(?is)<BODY.*the page you requested.*</BODY>': 0.10,
127
r'(?is)<BODY.*page.{1,50}unavailable.*</BODY>': 0.10,
128
r'(?is)<BODY.*request.{1,50}unavailable.*</BODY>': 0.10,
129
r'(?i)does not exist': 0.10,
134
# Note:- If new utility is added, add same utility here to uninstall properly.
136
BINS_LIST=['hpijs','hp-align','hp-colorcal','hp-faxsetup','hp-linefeedcal','hp-pkservice','hp-printsettings','hp-sendfax','hp-timedate','hp-check','hp-devicesettings','hp-firmware','hp-makecopies','hp-plugin','hp-probe','hp-setup','hp-toolbox','hp-check-plugin','hp-diagnose_plugin','hp-info','hp-makeuri','hp-pqdiag','hp-query','hp-systray','hp-unload','hp-clean','hp-fab','hp-levels','hp-mkuri','hp-print','hp-scan','hp-testpage','hp-wificonfig', 'hp-upgrade','hplip-info','hp-check-upgrade','hp-config_usb_printer','hp-diagnose_queues']
138
LIBS_LIST=['libhpmud.*','libhpip.*','sane/libsane-hpaio.*','cups/backend/hp','cups/backend/hpfax', 'cups/filter/hpcac', 'cups/filter/pstotiff','cups/filter/hpcups', 'cups/filter/hpcupsfax', 'cups/filter/hplipjs','cups/filter/hpps']
140
FILES_LIST=['/usr/share/ppd/HP/*','/etc/udev/rules.d/56-hpmud_support.rules', '/etc/udev/rules.d/40-hplip.rules', '/etc/udev/rules.d/56-hpmud_support.rules', '/etc/udev/rules.d/55-hpmud.rules', '/etc/udev/rules.d/86-hpmud-hp_*', '/etc/udev/rules.d/86-hpmud_plugin.rules', '/usr/share/cups/drv/hp/*','/usr/local/share/ppd/HP/*','/usr/local/share/cups/drv/hp/*' ,'/usr/share/applications/hplip.desktop', '/etc/xdg/autostart/hplip-systray.desktop', '/etc/hp/hplip.conf', '/usr/share/doc/hplip-*']
142
HPLIP_LIST=['*.py','*.pyc', 'base', 'copier','data','installer','pcard','ui4','ui','fax/*.py','fax/*.pyc','fax/pstotiff.convs','fax/pstotiff.types','fax/pstotiff','prnt/*.py', 'prnt/*.pyc', 'scan/*.py','scan/*.pyc']
144
PLUGIN_LIST=['fax/plugins/','prnt/pluginmode = INTERACTIVE_MODEs/','scan/plugins/']
145
PLUGIN_STATE =['/var/lib/hp/hplip.state']
153
for s in EXPECT_WORD_LIST:
155
p = re.compile(s, re.I)
157
EXPECT_LIST.append(s)
159
EXPECT_LIST.append(p)
161
OK_PROCESS_LIST = ['adept-notifier',
166
CONFIGURE_ERRORS = { 1 : "General/unknown error",
167
2 : "libusb not found",
168
3 : "cups-devel not found",
169
4 : "libnetsnmp not found",
170
5 : "netsnmp-devel not found",
171
6 : "python-devel not found",
172
7 : "pthread-devel not found",
173
8 : "ppdev-devel not found",
174
9 : "libcups not found",
175
10 : "libm not found",
176
11 : "libusb-devel not found",
177
12 : "sane-backends-devel not found",
178
13 : "libdbus not found",
179
14 : "dbus-devel not found",
180
15 : "fax requires dbus support",
181
102 : "libjpeg not found",
182
103 : "jpeg-devel not found",
183
104 : "libdi not found",
188
from functools import update_wrapper
189
except ImportError: # using Python version < 2.5
191
def newf(*args, **kw):
192
log.debug("TRACE: func=%s(), args=%s, kwargs=%s" % (f.__name__, args, kw))
193
return f(*args, **kw)
194
newf.__name__ = f.__name__
195
newf.__dict__.update(f.__dict__)
196
newf.__doc__ = f.__doc__
197
newf.__module__ = f.__module__
199
else: # using Python 2.5+
201
def newf(*args, **kw):
202
log.debug("TRACE: func=%s(), args=%s, kwargs=%s" % (f.__name__, args, kw))
203
return f(*args, **kw)
204
return update_wrapper(newf, f)
208
class CoreInstall(object):
209
def __init__(self, mode=MODE_INSTALLER, ui_mode=INTERACTIVE_MODE, ui_toolkit='qt4'):
212
self.ui_mode = ui_mode
214
self.version_description, self.version_public, self.version_internal = '', '', ''
216
self.endian = utils.LITTLE_ENDIAN
217
self.distro, self.distro_name, self.distro_version = DISTRO_UNKNOWN, '', DISTRO_VER_UNKNOWN
218
self.distro_version_supported = False
219
self.install_location = '/usr'
220
self.hplip_present = False
221
self.have_dependencies = {}
222
self.native_cups = True
226
self.network_connected = False
227
self.ui_toolkit = ui_toolkit
230
self.plugin_path = "/tmp"
231
self.plugin_version = '0.0.0'
232
self.plugin_name = ''
233
self.reload_dbus = False
237
'distros' : TYPE_LIST,
239
'versions' : TYPE_LIST,
240
'display_name' : TYPE_STRING,
241
'alt_names': TYPE_LIST,
242
'display': TYPE_BOOL,
243
'notes': TYPE_STRING,
244
'package_mgrs': TYPE_LIST,
245
'package_mgr_cmd':TYPE_STRING,
246
'pre_install_cmd': TYPE_LIST,
247
'pre_depend_cmd': TYPE_LIST,
248
'post_depend_cmd': TYPE_LIST,
249
'hpoj_remove_cmd': TYPE_STRING,
250
'hplip_remove_cmd': TYPE_STRING,
251
'su_sudo': TYPE_STRING,
252
'ppd_install': TYPE_STRING,
253
'udev_mode_fix': TYPE_BOOL,
254
'ppd_dir': TYPE_STRING,
255
'drv_dir' : TYPE_STRING,
256
'fix_ppd_symlink': TYPE_BOOL,
257
'code_name': TYPE_STRING,
258
'supported': TYPE_BOOL, # Supported by installer
259
'release_date': TYPE_STRING,
260
'packages': TYPE_LIST,
261
'commands': TYPE_LIST,
262
'same_as_version' : TYPE_STRING,
263
'scan_supported' : TYPE_BOOL,
264
'fax_supported' : TYPE_BOOL,
265
'pcard_supported' : TYPE_BOOL,
266
'network_supported' : TYPE_BOOL,
267
'parallel_supported' : TYPE_BOOL,
268
'usb_supported' : TYPE_BOOL,
269
'packaged_version': TYPE_STRING, # Version of HPLIP pre-packaged in distro
270
'cups_path_with_bitness' : TYPE_BOOL,
271
'ui_toolkit' : TYPE_STRING, # qt3 or qt4 [or gtk] or none
272
'policykit' : TYPE_BOOL,
273
'native_cups' : TYPE_BOOL,
274
'package_available' : TYPE_BOOL,
275
'package_arch' : TYPE_LIST,
276
'add_user_to_group': TYPE_STRING,
277
'open_mdns_port' : TYPE_LIST, # command to use to open mdns multicast port 5353
278
'acl_rules' : TYPE_BOOL, # Use ACL uDEV rules (Ubuntu 9.10+)
279
'libdir_path' : TYPE_STRING,
283
# 'name': ('description', [<option list>])
285
'hplip': ("HP Linux Imaging and Printing System", ['base', 'network', 'gui_qt4',
286
'fax', 'scan', 'docs']),
289
self.selected_component = 'hplip'
292
# name: (<required>, "<display_name>", [<dependency list>]), ...
294
'base': (True, 'Required HPLIP base components (including hpcups)', []), # HPLIP
295
'network' : (False, 'Network/JetDirect I/O', []),
296
'gui_qt4' : (False, 'Graphical User Interfaces (Qt4)', []),
297
'fax' : (False, 'PC Send Fax support', []),
298
'scan': (False, 'Scanning support', []),
299
'docs': (False, 'HPLIP documentation (HTML)', []),
300
'policykit': (False, 'Administrative policy framework', []),
304
# holds whether the user has selected (turned on each option)
305
# initial values are defaults (for GUI only)
306
self.selected_options = {
314
'native_cups': False,
318
# 'name': (<required for option>, [<option list>], <display_name>, <check_func>, <runtime/compiletime>), ...
319
# Note: any change to the list of dependencies must be reflected in base/distros.py
320
self.dependencies = {
321
# Required base packages
322
'libjpeg': (True, ['base'], "libjpeg - JPEG library", self.check_libjpeg, DEPENDENCY_RUN_AND_COMPILE_TIME),
323
'libtool': (True, ['base'], "libtool - Library building support services", self.check_libtool, DEPENDENCY_COMPILE_TIME),
324
'cups' : (True, ['base'], 'CUPS - Common Unix Printing System', self.check_cups, DEPENDENCY_RUN_TIME),
325
'cups-devel': (True, ['base'], 'CUPS devel- Common Unix Printing System development files', self.check_cups_devel, DEPENDENCY_COMPILE_TIME),
326
'cups-image': (True, ['base'], "CUPS image - CUPS image development files", self.check_cups_image, DEPENDENCY_COMPILE_TIME),
327
'gcc' : (True, ['base'], 'gcc - GNU Project C and C++ Compiler', self.check_gcc, DEPENDENCY_COMPILE_TIME),
328
'make' : (True, ['base'], "make - GNU make utility to maintain groups of programs", self.check_make, DEPENDENCY_COMPILE_TIME),
329
'python-devel' : (True, ['base'], "Python devel - Python development files", self.check_python_devel, DEPENDENCY_COMPILE_TIME),
330
'libpthread' : (True, ['base'], "libpthread - POSIX threads library", self.check_libpthread, DEPENDENCY_RUN_AND_COMPILE_TIME),
331
'python2x': (True, ['base'], "Python 2.2 or greater - Python programming language", self.check_python2x, DEPENDENCY_RUN_AND_COMPILE_TIME),
332
'python-xml' : (True, ['base'], "Python XML libraries", self.check_python_xml, DEPENDENCY_RUN_TIME),
333
'gs': (True, ['base'], "GhostScript - PostScript and PDF language interpreter and previewer", self.check_gs, DEPENDENCY_RUN_TIME),
334
'libusb': (True, ['base'], "libusb - USB library", self.check_libusb, DEPENDENCY_RUN_AND_COMPILE_TIME),
336
# Optional base packages
337
'cups-ddk': (False, ['base'], "CUPS DDK - CUPS driver development kit", self.check_cupsddk, DEPENDENCY_RUN_TIME), # req. for .drv PPD installs
340
# Required scan packages
341
'sane': (True, ['scan'], "SANE - Scanning library", self.check_sane, DEPENDENCY_RUN_TIME),
342
'sane-devel' : (True, ['scan'], "SANE - Scanning library development files", self.check_sane_devel, DEPENDENCY_COMPILE_TIME),
344
# Optional scan packages
345
'xsane': (False, ['scan'], "xsane - Graphical scanner frontend for SANE", self.check_xsane, DEPENDENCY_RUN_TIME),
346
'scanimage': (False, ['scan'], "scanimage - Shell scanning program", self.check_scanimage, DEPENDENCY_RUN_TIME),
347
'pil': (False, ['scan'], "PIL - Python Imaging Library (required for commandline scanning with hp-scan)", self.check_pil, DEPENDENCY_RUN_TIME),
349
# Required fax packages
350
'python23': (True, ['fax'], "Python 2.3 or greater - Required for fax functionality", self.check_python23, DEPENDENCY_RUN_TIME),
351
'dbus': (True, ['fax'], "DBus - Message bus system", self.check_dbus, DEPENDENCY_RUN_AND_COMPILE_TIME),
352
'python-dbus': (True, ['fax'], "Python DBus - Python bindings for DBus", self.check_python_dbus, DEPENDENCY_RUN_TIME),
354
# Optional fax packages
355
'reportlab': (False, ['fax'], "Reportlab - PDF library for Python", self.check_reportlab, DEPENDENCY_RUN_TIME),
357
# Required and optional qt4 GUI packages
358
'pyqt4': (True, ['gui_qt4'], "PyQt 4- Qt interface for Python (for Qt version 4.x)", self.check_pyqt4, DEPENDENCY_RUN_TIME), # PyQt 4.x )
359
'pyqt4-dbus' : (True, ['gui_qt4'], "PyQt 4 DBus - DBus Support for PyQt4", self.check_pyqt4_dbus, DEPENDENCY_RUN_TIME),
360
'policykit': (False, ['gui_qt4'], "PolicyKit - Administrative policy framework", self.check_policykit, DEPENDENCY_RUN_TIME), # optional for non-sudo behavior of plugins (only optional for Qt4 option)
361
'python-notify' : (False, ['gui_qt4'], "Python libnotify - Python bindings for the libnotify Desktop notifications", self.check_pynotify, DEPENDENCY_RUN_TIME), # Optional for libnotify style popups from hp-systray
363
# Required network I/O packages
364
'libnetsnmp-devel': (True, ['network'], "libnetsnmp-devel - SNMP networking library development files", self.check_libnetsnmp, DEPENDENCY_RUN_AND_COMPILE_TIME),
365
'libcrypto': (True, ['network'], "libcrypto - OpenSSL cryptographic library", self.check_libcrypto, DEPENDENCY_RUN_AND_COMPILE_TIME),
368
for opt in self.options:
370
for d in self.dependencies:
371
if opt in self.dependencies[d][1]:
372
self.options[opt][2].append(d)
376
self.distros_index = {}
377
for d in self.distros:
378
self.distros_index[self.distros[d]['index']] = d
381
def init(self, callback=None):
382
if callback is not None:
383
callback("Init...\n")
387
# Package manager names
388
self.package_mgrs = []
389
for d in self.distros:
392
for a in self.distros[d].get('package_mgrs', []):
393
if a and a not in self.package_mgrs:
394
self.package_mgrs.append(a)
396
self.version_description, self.version_public, self.version_internal = self.get_hplip_version()
397
log.debug("HPLIP Description=%s Public version=%s Internal version = %s" %
398
(self.version_description, self.version_public, self.version_internal))
401
# is each dependency satisfied?
402
# start with each one 'No'
403
for d in self.dependencies:
405
self.have_dependencies[d] = False
408
self.distro_changed()
410
if callback is not None:
411
callback("Distro: %s\n" % self.distro)
413
self.check_dependencies(callback)
415
for d in self.dependencies:
418
log.debug("have %s = %s" % (d, self.have_dependencies[d]))
420
if callback is not None:
421
callback("Result: %s = %s\n" % (d, self.have_dependencies[d]))
423
pid, cmdline = self.check_pkg_mgr()
425
log.debug("Running package manager: %s (%d)" % (cmdline, pid) )
427
self.bitness = utils.getBitness()
428
log.debug("Bitness = %d" % self.bitness)
432
self.endian = utils.getEndian()
433
log.debug("Endian = %d" % self.endian)
437
self.distro_name = self.distros_index[self.distro]
438
self.distro_version_supported = self.get_distro_ver_data('supported', False)
440
log.debug("Distro = %s Distro Name = %s Display Name= %s Version = %s Supported = %s" %
441
(self.distro, self.distro_name, self.distros[self.distro_name]['display_name'],
442
self.distro_version, self.distro_version_supported))
446
self.hplip_present = self.check_hplip()
447
log.debug("HPLIP (prev install) = %s" % self.hplip_present)
449
status, output = self.run('cups-config --version')
450
self.cups_ver = output.strip()
451
log.debug("CUPS version = %s" % self.cups_ver)
453
if self.distro_name == "ubuntu":
454
self.reload_dbus = True
456
log.debug("DBUS configuration reload possible? %s" % self.reload_dbus)
458
status, self.sys_uname_info = self.run('uname -a')
459
self.sys_uname_info = self.sys_uname_info.replace('\n', '')
460
log.debug(self.sys_uname_info)
462
# Record the installation time/date and version.
463
# Also has the effect of making the .hplip.conf file user r/w
464
# on the 1st run so that running hp-setup as root doesn't lock
465
# the user out of owning the file
466
user_conf.set('installation', 'date_time', time.strftime("%x %H:%M:%S", time.localtime()))
467
user_conf.set('installation', 'version', self.version_public)
469
if callback is not None:
473
def init_for_docs(self, distro_name, version, bitness=32):
474
self.distro_name = distro_name
475
self.distro_version = version
478
self.distro = self.distros[distro_name]['index']
480
log.error("Invalid distro name: %s" % distro_name)
483
self.bitness = bitness
485
for d in self.dependencies:
486
self.have_dependencies[d] = True
488
self.enable_ppds = self.get_distro_ver_data('ppd_install', 'ppd') == 'ppd'
489
self.ppd_dir = self.get_distro_ver_data('ppd_dir')
490
self.drv_dir = self.get_distro_ver_data('drv_dir')
492
self.distro_version_supported = True # for manual installs
495
def check_dependencies(self, callback=None):
498
for d in self.dependencies:
501
log.debug("Checking for dependency '%s'...\n" % d)
503
if callback is not None:
504
callback("Checking: %s\n" % d)
506
self.have_dependencies[d] = self.dependencies[d][3]()
507
log.debug("have %s = %s" % (d, self.have_dependencies[d]))
512
def password_func(self):
515
elif self.ui_mode == INTERACTIVE_MODE:
517
return getpass.getpass("Enter password: ")
522
def run(self, cmd, callback=None, timeout=300): # ==> status, output
525
output = cStringIO.StringIO()
528
check_timeout = not (cmd.startswith('xterm') or cmd.startswith('gnome-terminal'))
531
child = pexpect.spawn(cmd, timeout=1)
532
except pexpect.ExceptionPexpect:
542
i = child.expect_list(EXPECT_LIST)
552
if callback is not None:
553
if callback(cb): # cancel
558
span = int(time.time()-start)
562
log.debug("No output seen in %d secs" % span)
565
log.error("No output seen in over %d sec... (Is the CD-ROM/DVD source repository enabled? It shouldn't be!)" % timeout)
567
child.terminate(force=True)
571
ok, ret = True, output.getvalue()
574
elif i == 1: # TIMEOUT
577
elif i == 2: # zypper "Continue?"
578
child.sendline("YES")
581
child.sendline(self.password)
583
except (Exception, pexpect.ExceptionPexpect):
595
return child.exitstatus, ret
600
def get_distro(self):
601
log.debug("Determining distro...")
602
self.distro, self.distro_version = DISTRO_UNKNOWN, '0.0'
606
lsb_release = utils.which("lsb_release")
609
log.debug("Using 'lsb_release -is/-rs'")
610
cmd = os.path.join(lsb_release, "lsb_release")
611
status, name = self.run(cmd + ' -is')
612
name = name.lower().strip()
613
log.debug("Distro name=%s" % name)
615
if not status and name:
616
status, ver = self.run(cmd + ' -rs')
617
ver = ver.lower().strip()
618
log.debug("Distro version=%s" % ver)
620
if not status and ver:
621
for d in self.distros:
622
if name.find(d) > -1:
623
self.distro = self.distros[d]['index']
625
self.distro_version = ver
630
name = file('/etc/issue', 'r').read().lower().strip()
632
# Some O/Ss don't have /etc/issue (Mac)
633
self.distro, self.distro_version = DISTRO_UNKNOWN, '0.0'
635
for d in self.distros:
636
if name.find(d) > -1:
637
self.distro = self.distros[d]['index']
640
for x in self.distros[d].get('alt_names', ''):
641
if x and name.find(x) > -1:
642
self.distro = self.distros[d]['index']
650
for n in name.split():
653
m = '.'.join(n.split('.')[:2])
661
self.distro_version = '0.0'
663
self.distro_version = m
666
self.distro_version = m
669
log.debug("/etc/issue: %s %s" % (name, self.distro_version))
671
log.debug("distro=%d, distro_version=%s" % (self.distro, self.distro_version))
674
def distro_changed(self):
675
ppd_install = self.get_distro_ver_data('ppd_install', 'ppd')
677
if ppd_install not in ('ppd', 'drv'):
678
log.warning("Invalid ppd_install value: %s" % ppd_install)
680
self.enable_ppds = (ppd_install == 'ppd')
682
log.debug("Enable PPD install: %s (False=drv)" % self.enable_ppds)
684
self.ppd_dir = self.get_distro_ver_data('ppd_dir')
686
self.drv_dir = self.get_distro_ver_data('drv_dir')
687
if not self.enable_ppds and not self.drv_dir:
688
log.warning("Invalid drv_dir value: %s" % self.drv_dir)
690
self.distro_version_supported = self.get_distro_ver_data('supported', False)
691
self.selected_options['fax'] = self.get_distro_ver_data('fax_supported', True)
692
self.selected_options['network'] = self.get_distro_ver_data('network_supported', True)
693
self.selected_options['scan'] = self.get_distro_ver_data('scan_supported', True)
694
self.selected_options['policykit'] = self.get_distro_ver_data('policykit', False)
695
self.native_cups = self.get_distro_ver_data('native_cups', False)
697
# Adjust required flag based on the distro ver ui_toolkit value
698
ui_toolkit = self.get_distro_ver_data('ui_toolkit', 'qt4').lower()
700
if ui_toolkit == 'qt4':
701
log.debug("Default UI toolkit: Qt4")
702
self.ui_toolkit = 'qt4'
703
self.selected_options['gui_qt4'] = True
707
self.selected_options['gui_qt4'] = False
709
# Override with --qt4 command args
710
if self.enable is not None:
711
if 'qt4' in self.enable:
712
log.debug("User selected UI toolkit: Qt4")
713
self.ui_toolkit = 'qt4'
714
self.selected_options['gui_qt4'] = True
716
if self.disable is not None:
717
if 'qt4' in self.disable:
718
log.debug("User deselected UI toolkit: Qt4")
719
self.selected_options['gui_qt4'] = False
722
def __fixup_data(self, key, data):
723
field_type = self.FIELD_TYPES.get(key, TYPE_STRING)
724
#log.debug("%s (%s) %d" % (key, data, field_type))
726
if field_type == TYPE_BOOL:
727
return utils.to_bool(data)
729
elif field_type == TYPE_STRING:
730
if type('') == type(data):
735
elif field_type == TYPE_INT:
741
elif field_type == TYPE_LIST:
742
return [x for x in data.split(',') if x]
745
def load_distros(self):
746
if self.mode == MODE_INSTALLER:
747
distros_dat_file = os.path.join('installer', 'distros.dat')
749
elif self.mode == MODE_CREATE_DOCS:
750
distros_dat_file = os.path.join('..', '..', 'installer', 'distros.dat')
753
distros_dat_file = os.path.join(prop.home_dir, 'installer', 'distros.dat')
755
if not os.path.exists(distros_dat_file):
756
log.debug("DAT file not found at %s. Using local relative path..." % distros_dat_file)
757
distros_dat_file = os.path.join('installer', 'distros.dat')
759
distros_dat = ConfigBase(distros_dat_file)
760
distros_list = self.__fixup_data('distros', distros_dat.get('distros', 'distros'))
761
log.debug(distros_list)
763
for distro in distros_list:
767
if not distros_dat.has_section(distro):
768
log.debug("Missing distro section in distros.dat: [%s]" % distro)
771
for key in distros_dat.keys(distro):
772
d[key] = self.__fixup_data(key, distros_dat.get(distro, key))
774
self.distros[distro] = d
775
versions = self.__fixup_data("versions", distros_dat.get(distro, 'versions'))
776
self.distros[distro]['versions'] = {}
779
same_as_version, supported = False, True
781
ver_section = "%s:%s" % (distro, ver)
783
if not distros_dat.has_section(ver_section):
784
log.error("Missing version section in distros.dat: [%s:%s]" % (distro, ver))
787
if 'same_as_version' in distros_dat.keys(ver_section):
788
same_as_version = True
790
supported = self.__fixup_data('supported', distros_dat.get(ver_section, 'supported'))
792
for key in distros_dat.keys(ver_section):
793
v[key] = self.__fixup_data(key, distros_dat.get(ver_section, key))
795
self.distros[distro]['versions'][ver] = v
796
self.distros[distro]['versions'][ver]['dependency_cmds'] = {}
798
if same_as_version: # or not supported:
801
for dep in self.dependencies:
803
dep_section = "%s:%s:%s" % (distro, ver, dep)
805
if not distros_dat.has_section(dep_section) and not same_as_version:
806
log.debug("Missing dependency section in distros.dat: [%s:%s:%s]" % (distro, ver, dep))
812
for key in distros_dat.keys(dep_section):
813
dd[key] = self.__fixup_data(key, distros_dat.get(dep_section, key))
815
self.distros[distro]['versions'][ver]['dependency_cmds'][dep] = dd
817
versions = self.distros[distro]['versions']
819
ver_section = "%s:%s" % (distro, ver)
821
if 'same_as_version' in distros_dat.keys(ver_section):
822
v = self.__fixup_data("same_as_version", distros_dat.get(ver_section, 'same_as_version'))
823
log.debug("Setting %s:%s to %s:%s" % (distro, ver, distro, v))
826
vv = self.distros[distro]['versions'][v].copy()
827
vv['same_as_version'] = v
828
self.distros[distro]['versions'][ver] = vv
830
log.debug("Missing 'same_as_version=' version in distros.dat for section [%s:%s]." % (distro, v))
834
#pprint.pprint(self.distros)
836
def pre_install(self):
840
def pre_depend(self):
844
def check_python2x(self):
845
py_ver = sys.version_info
846
py_major_ver, py_minor_ver = py_ver[:2]
847
log.debug("Python ver=%d.%d" % (py_major_ver, py_minor_ver))
848
return py_major_ver >= 2
852
return check_tool('gcc --version', 0) and check_tool('g++ --version', 0)
855
def check_make(self):
856
return check_tool('make --version', 3.0)
859
def check_libusb(self):
860
if not check_lib('libusb'):
863
return len(locate_file_contains("usb.h", '/usr/include', 'usb_init(void)'))
866
def check_libjpeg(self):
867
return check_lib("libjpeg") and check_file("jpeglib.h")
870
def check_libcrypto(self):
871
return check_lib("libcrypto") and check_file("crypto.h")
874
def check_libpthread(self):
875
return check_lib("libpthread") and check_file("pthread.h")
878
def check_libnetsnmp(self):
879
return check_lib("libnetsnmp") and check_file("net-snmp-config.h")
882
def check_reportlab(self):
884
log.debug("Trying to import 'reportlab'...")
887
ver = reportlab.Version
891
log.debug("Can't determine version.")
894
log.debug("Version: %.1f" % ver_f)
896
log.debug("Success.")
906
def check_python23(self):
907
py_ver = sys.version_info
908
py_major_ver, py_minor_ver = py_ver[:2]
909
log.debug("Python ver=%d.%d" % (py_major_ver, py_minor_ver))
910
return py_major_ver >= 2 and py_minor_ver >= 3
913
def check_python_xml(self):
915
import xml.parsers.expat
922
def check_sane(self):
923
return check_lib('libsane')
926
def check_sane_devel(self):
927
return len(locate_file_contains("sane.h", '/usr/include', 'extern SANE_Status sane_init'))
930
def check_xsane(self):
931
if os.getenv('DISPLAY'):
932
return check_tool('xsane --version', 0.9) # will fail if X not running...
934
return bool(utils.which("xsane")) # ...so just see if it installed somewhere
937
def check_scanimage(self):
938
return check_tool('scanimage --version', 1.0)
942
return check_tool('gs -v', 7.05)
945
def check_pyqt4(self):
946
if self.ui_toolkit == 'qt4':
958
def check_pyqt4_dbus(self):
959
if self.ui_toolkit == 'qt4':
961
from dbus.mainloop.qt import DBusQtMainLoop
970
def check_python_devel(self):
971
return check_file('Python.h')
974
def check_pynotify(self):
983
def check_python_dbus(self):
984
log.debug("Checking for python-dbus (>= 0.80)...")
989
log.debug("Version: %s" % '.'.join([str(x) for x in dbus.version]))
990
return ver >= (0,80,0)
992
except AttributeError:
994
ver = dbus.__version__
995
log.debug("Version: %s" % dbus.__version__)
996
log.debug("HPLIP requires dbus version > 0.80.")
999
except AttributeError:
1000
log.debug("Unknown version. HPLIP requires dbus version > 0.80.")
1007
def check_python_ctypes(self):
1015
def check_dbus(self):
1016
log.debug("Checking for dbus running and header files present (dbus-devel)...")
1017
return check_ps(['dbus-daemon']) and \
1018
len(locate_file_contains("dbus-message.h", '/usr/include', 'dbus_message_new_signal'))
1021
def check_cups_devel(self):
1022
return check_file('cups.h') and bool(utils.which('lpr'))
1025
def check_cups(self):
1026
status, output = self.run('lpstat -r')
1028
log.debug("CUPS is not running.")
1031
log.debug("CUPS is running.")
1035
def check_cups_image(self):
1036
return check_file("raster.h", "/usr/include/cups")
1039
def check_hplip(self):
1040
log.debug("Checking for HPLIP...")
1041
return locate_files('hplip.conf', '/etc/hp')
1044
def check_hpssd(self):
1045
log.debug("Checking for hpssd...")
1046
return check_ps(['hpssd'])
1049
def check_libtool(self):
1050
log.debug("Checking for libtool...")
1051
return check_tool('libtool --version')
1054
def check_pil(self):
1055
log.debug("Checking for PIL...")
1063
def check_cupsddk(self):
1064
log.debug("Checking for cups-ddk...")
1065
# TODO: Compute these paths some way or another...
1066
#return check_tool("/usr/lib/cups/driver/drv list") and os.path.exists("/usr/share/cupsddk/include/media.defs")
1067
return (check_file('drv', "/usr/lib/cups/driver") or check_file('drv', "/usr/lib64/cups/driver")) and \
1068
check_file('media.defs', "/usr/share/cupsddk/include")
1071
def check_policykit(self):
1072
log.debug("Checking for PolicyKit...")
1073
return (check_file('PolicyKit.conf', "/etc/PolicyKit") and check_file('org.gnome.PolicyKit.AuthorizationManager.service', "/usr/share/dbus-1/services")) or (check_file('50-localauthority.conf', "/etc/polkit-1/localauthority.conf.d") and check_file('org.freedesktop.PolicyKit1.service', "/usr/share/dbus-1/system-services"))
1075
def check_pkg_mgr(self):
1077
Check if any pkg mgr processes are running
1079
log.debug("Searching for '%s' in running processes..." % self.package_mgrs)
1081
processes = get_process_list()
1083
for pid, cmdline in processes:
1084
for p in self.package_mgrs:
1086
for k in OK_PROCESS_LIST:
1092
log.debug("Found: %s (%d)" % (cmdline, pid))
1093
return (pid, cmdline)
1095
log.debug("Not found")
1099
def get_hplip_version(self):
1100
self.version_description, self.version_public, self.version_internal = '', '', ''
1102
if self.mode == MODE_INSTALLER:
1103
ac_init_pat = re.compile(r"""AC_INIT\(\[(.*?)\], *\[(.*?)\], *\[(.*?)\], *\[(.*?)\] *\)""", re.IGNORECASE)
1106
config_in = open('./configure.in', 'r')
1108
self.version_description, self.version_public, self.version_internal = \
1109
'', sys_conf.get('configure', 'internal-tag', '0.0.0'), prop.installed_version
1112
if c.startswith("AC_INIT"):
1113
match_obj = ac_init_pat.search(c)
1114
self.version_description = match_obj.group(1)
1115
self.version_public = match_obj.group(2)
1116
self.version_internal = match_obj.group(3)
1117
name = match_obj.group(4)
1123
log.error("Invalid archive!")
1128
self.version_description, self.version_public, self.version_internal = \
1129
'', sys_conf.get('configure', 'internal-tag', '0.0.0'), prop.installed_version
1131
self.version_description, self.version_public, self.version_internal = '', '', ''
1133
return self.version_description, self.version_public, self.version_internal
1136
def configure(self):
1137
configure_cmd = './configure'
1139
dbus_avail = self.have_dependencies['dbus'] and self.have_dependencies['python-dbus']
1140
configuration['network-build'] = self.selected_options['network']
1141
configuration['fax-build'] = self.selected_options['fax'] and dbus_avail
1142
configuration['dbus-build'] = dbus_avail
1143
configuration['qt4'] = self.selected_options['gui_qt4']
1144
configuration['scan-build'] = self.selected_options['scan']
1145
configuration['doc-build'] = self.selected_options['docs']
1146
configuration['policykit'] = self.selected_options['policykit']
1148
# Setup printer driver configure flags based on distro data...
1149
if self.native_cups: # hpcups
1150
configuration['hpcups-install'] = True
1151
configuration['hpijs-install'] = False
1152
configuration['foomatic-ppd-install'] = False
1153
configuration['foomatic-drv-install'] = False
1155
if self.enable_ppds:
1156
configuration['cups-ppd-install'] = True
1157
configuration['cups-drv-install'] = False
1159
configuration['cups-ppd-install'] = False
1160
configuration['cups-drv-install'] = True
1162
else: # HPIJS/foomatic
1163
configuration['hpcups-install'] = False
1164
configuration['hpijs-install'] = True
1165
configuration['cups-ppd-install'] = False
1166
configuration['cups-drv-install'] = False
1168
if self.enable_ppds:
1169
configuration['foomatic-ppd-install'] = True
1170
configuration['foomatic-drv-install'] = False
1172
configuration['foomatic-ppd-install'] = False
1173
configuration['foomatic-drv-install'] = True
1176
# ... and then override and adjust for consistency with passed in parameters
1177
if self.enable is not None:
1178
for c in self.enable:
1179
if c == 'hpcups-install':
1180
configuration['hpijs-install'] = False
1181
configuration['foomatic-ppd-install'] = False
1182
configuration['foomatic-drv-install'] = False
1183
elif c == 'hpijs-install':
1184
configuration['hpcups-install'] = False
1185
configuration['cups-ppd-install'] = False
1186
configuration['cups-drv-install'] = False
1187
elif c == 'foomatic-ppd-install':
1188
configuration['foomatic-drv-install'] = False
1189
elif c == 'foomatic-drv-install':
1190
configuration['foomatic-ppd-install'] = False
1191
elif c == 'cups-ppd-install':
1192
configuration['cups-drv-install'] = False
1193
elif c == 'cups-drv-install':
1194
configuration['cups-ppd-install'] = False
1196
if self.disable is not None:
1197
for c in self.disable:
1198
if c == 'hpcups-install':
1199
configuration['hpijs-install'] = True
1200
configuration['cups-ppd-install'] = False
1201
configuration['cups-drv-install'] = False
1202
elif c == 'hpijs-install':
1203
configuration['hpcups-install'] = True
1204
configuration['foomatic-ppd-install'] = False
1205
configuration['foomatic-drv-install'] = False
1206
elif c == 'foomatic-ppd-install':
1207
configuration['foomatic-drv-install'] = True
1208
elif c == 'foomatic-drv-install':
1209
configuration['foomatic-ppd-install'] = True
1210
elif c == 'cups-ppd-install':
1211
configuration['cups-drv-install'] = True
1212
elif c == 'cups-drv-install':
1213
configuration['cups-ppd-install'] = True
1215
if self.ppd_dir is not None:
1216
configure_cmd += ' --with-hpppddir=%s' % self.ppd_dir
1218
libdir_path = self.get_distro_ver_data('libdir_path',False)
1219
if libdir_path and self.bitness == 64:
1220
configure_cmd += ' --libdir=%s' % (libdir_path)
1221
elif self.bitness == 64:
1222
configure_cmd += ' --libdir=/usr/lib64'
1224
configure_cmd += ' --prefix=%s' % self.install_location
1226
if self.get_distro_ver_data('cups_path_with_bitness', False) and self.bitness == 64:
1227
configure_cmd += ' --with-cupsbackenddir=/usr/lib64/cups/backend --with-cupsfilterdir=/usr/lib64/cups/filter'
1229
if self.get_distro_ver_data('acl_rules', False):
1230
configure_cmd += ' --enable-udev-acl-rules'
1232
if self.enable is not None:
1233
for c in self.enable:
1234
configuration[c] = True
1236
if self.disable is not None:
1237
for c in self.disable:
1238
configuration[c] = False
1240
for c in configuration:
1241
if configuration[c]:
1242
configure_cmd += ' --enable-%s' % c
1244
configure_cmd += ' --disable-%s' % c
1246
return configure_cmd
1248
def configure_html(self):
1249
configure_cmd = './configure'
1250
configure_cmd += ' --prefix=/usr'
1251
configure_cmd += ' --with-hpppddir=%s' % self.ppd_dir
1253
if self.bitness == 64:
1254
configure_cmd += ' --libdir=/usr/lib64'
1256
self.ui_toolkit = self.get_distro_ver_data('ui_toolkit')
1257
if self.ui_toolkit is not None and self.ui_toolkit == 'qt3':
1258
configure_cmd += ' --enable-qt3 --disable-qt4'
1260
configure_cmd += ' --enable-qt4'
1262
self.native_cups = self.get_distro_ver_data('native_cups')
1263
if self.native_cups is not None and self.native_cups == 1:
1264
configure_cmd += ' --enable-hpcups-install --enable-cups-drv-install --enable-cups-ppd-install --disable-hpijs-install --disable-foomatic-drv-install --disable-foomatic-ppd-install --disable-foomatic-rip-hplip-install'
1266
configure_cmd += ' --disable-hpcups-install --disable-cups-drv-install --disable-cups-ppd-install --enable-hpijs-install --enable-foomatic-drv-install --enable-foomatic-ppd-install --enable-foomatic-rip-hplip-install'
1268
self.fax_supported = self.get_distro_ver_data('fax_supported')
1269
if self.fax_supported is None:
1270
configure_cmd += ' --disable-fax-build --disable-dbus-build'
1272
configure_cmd += ' --enable-fax-build --enable-dbus-build'
1274
self.network_supported = self.get_distro_ver_data('network_supported')
1275
if self.network_supported is None:
1276
configure_cmd += ' --disable-network-build'
1278
configure_cmd += ' --enable-network-build'
1280
self.scan_supported = self.get_distro_ver_data('scan_supported')
1281
if self.scan_supported is None:
1282
configure_cmd += ' --disable-scan-build'
1284
configure_cmd += ' --enable-scan-build'
1286
self.policykit = self.get_distro_ver_data('policykit')
1287
if self.policykit is not None and self.policykit == 1:
1288
configure_cmd += ' --enable-policykit'
1290
configure_cmd += ' --disable-policykit'
1292
return configure_cmd
1294
def configure_qt4(self):
1295
configure_cmd = './configure'
1296
configure_cmd += ' --prefix=/usr'
1297
configure_cmd += ' --with-hpppddir=%s' % self.ppd_dir
1299
if self.bitness == 64:
1300
configure_cmd += ' --libdir=/usr/lib64'
1302
self.ui_toolkit = self.get_distro_ver_data('ui_toolkit')
1303
if self.ui_toolkit is not None and self.ui_toolkit == 'qt3':
1304
configure_cmd += ' --enable-qt3 --disable-qt4'
1306
configure_cmd += ' --enable-qt4'
1308
self.native_cups = self.get_distro_ver_data('native_cups')
1309
self.ppd_install = self.get_distro_ver_data('ppd_install')
1310
if self.native_cups is not None and self.native_cups == 1:
1311
configure_cmd += ' --enable-hpcups-install'
1312
if self.ppd_install == 'drv':
1313
configure_cmd += ' --enable-cups-drv-install --disable-cups-ppd-install'
1315
configure_cmd += ' --enable-cups-ppd-install --disable-cups-drv-install'
1316
configure_cmd += ' --disable-hpijs-install --disable-foomatic-drv-install --disable-foomatic-ppd-install --disable-foomatic-rip-hplip-install'
1318
configure_cmd += ' --enable-hpijs-install'
1319
if self.ppd_install == 'drv':
1320
configure_cmd += ' --enable-foomatic-drv-install --disable-foomatic-ppd-install'
1322
configure_cmd += ' --enable-foomatic-ppd-install --disable-foomatic-drv-install'
1323
configure_cmd += ' --enable-foomatic-rip-hplip-install --disable-hpcups-install --disable-cups-drv-install --disable-cups-ppd-install'
1325
self.fax_supported = self.get_distro_ver_data('fax_supported')
1326
if self.fax_supported is None:
1327
configure_cmd += ' --disable-fax-build --disable-dbus-build'
1329
configure_cmd += ' --enable-fax-build --enable-dbus-build'
1331
self.network_supported = self.get_distro_ver_data('network_supported')
1332
if self.network_supported is None:
1333
configure_cmd += ' --disable-network-build'
1335
configure_cmd += ' --enable-network-build'
1337
self.scan_supported = self.get_distro_ver_data('scan_supported')
1338
if self.scan_supported is None:
1339
configure_cmd += ' --disable-scan-build'
1341
configure_cmd += ' --enable-scan-build'
1343
self.policykit = self.get_distro_ver_data('policykit')
1344
if self.policykit is not None and self.policykit == 1:
1345
configure_cmd += ' --enable-policykit'
1347
configure_cmd += ' --disable-policykit'
1349
return configure_cmd
1352
def restart_cups(self):
1353
if os.path.exists('/etc/init.d/cups'):
1354
cmd = self.su_sudo() % '/etc/init.d/cups restart'
1356
elif os.path.exists('/etc/init.d/cupsys'):
1357
cmd = self.su_sudo() % '/etc/init.d/cupsys restart'
1360
cmd = self.su_sudo() % 'killall -HUP cupsd'
1365
def stop_hplip(self):
1366
return self.su_sudo() % "/etc/init.d/hplip stop"
1370
if os.geteuid() == 0:
1374
cmd = self.distros[self.distro_name]['su_sudo']
1383
def su_sudo_str(self):
1384
return self.get_distro_data('su_sudo', 'su')
1387
def build_cmds(self):
1388
return [self.configure(),
1391
self.su_sudo() % 'make install']
1394
def get_distro_ver_data(self, key, default=None):
1396
return self.distros[self.distro_name]['versions'][self.distro_version].get(key, None) or \
1397
self.distros[self.distro_name].get(key, None) or default
1404
def get_distro_data(self, key, default=None):
1406
return self.distros[self.distro_name].get(key, None) or default
1411
def get_ver_data(self, key, default=None):
1413
return self.distros[self.distro_name]['versions'][self.distro_version].get(key, None) or default
1420
def get_dependency_data(self, dependency):
1421
dependency_cmds = self.get_ver_data("dependency_cmds", {})
1422
dependency_data = dependency_cmds.get(dependency, {})
1423
packages = dependency_data.get('packages', [])
1424
commands = dependency_data.get('commands', [])
1425
return packages, commands
1428
def get_dependency_commands(self):
1429
dd = self.dependencies.keys()
1431
commands_to_run = []
1432
packages_to_install = []
1433
overall_commands_to_run = []
1436
for opt in self.dependencies[d][1]:
1437
if self.selected_options[opt]:
1440
pkgs, cmds = self.get_dependency_data(d)
1444
if not p in packages_to_install:
1445
packages_to_install.append(p)
1448
commands_to_run.extend(cmds)
1450
package_mgr_cmd = self.get_distro_data('package_mgr_cmd')
1452
overall_commands_to_run.extend(commands_to_run)
1455
packages_to_install = ' '.join(packages_to_install)
1456
overall_commands_to_run.append(utils.cat(package_mgr_cmd))
1458
if not overall_commands_to_run:
1459
log.error("No cmds/pkgs")
1461
return overall_commands_to_run
1464
def distro_known(self):
1465
return self.distro != DISTRO_UNKNOWN and self.distro_version != DISTRO_VER_UNKNOWN
1468
def distro_supported(self):
1469
if self.mode == MODE_INSTALLER:
1470
return self.distro != DISTRO_UNKNOWN and self.distro_version != DISTRO_VER_UNKNOWN and self.get_ver_data('supported', False)
1472
return True # For docs (manual install)
1475
def sort_vers(self, x, y):
1477
return cmp(float(x), float(y))
1482
def running_as_root(self):
1483
return os.geteuid() == 0
1486
def show_release_notes_in_browser(self):
1487
url = "file://%s" % os.path.join(os.getcwd(), 'doc', 'release_notes.html')
1489
status, output = self.run("xhost +")
1493
def count_num_required_missing_dependencies(self):
1495
for d, desc, opt in self.missing_required_dependencies():
1496
num_req_missing += 1
1497
return num_req_missing
1500
def count_num_optional_missing_dependencies(self):
1502
for d, desc, req, opt in self.missing_optional_dependencies():
1503
num_opt_missing += 1
1504
return num_opt_missing
1507
def missing_required_dependencies(self): # missing req. deps in req. options
1508
for opt in self.components[self.selected_component][1]:
1509
if self.options[opt][0]: # required options
1510
for d in self.options[opt][2]: # dependencies for option
1511
if self.dependencies[d][0]: # required option
1512
if not self.have_dependencies[d]: # missing
1513
log.debug("Missing required dependency: %s" % d)
1514
yield d, self.dependencies[d][2], opt
1515
# depend, desc, option
1517
def missing_optional_dependencies(self):
1518
# missing deps in opt. options
1519
for opt in self.components[self.selected_component][1]:
1520
if not self.options[opt][0]: # not required option
1521
if self.selected_options[opt]: # only for options that are ON
1522
for d in self.options[opt][2]: # dependencies
1523
if not self.have_dependencies[d]: # missing dependency
1524
log.debug("Missing optional dependency: %s" % d)
1525
yield d, self.dependencies[d][2], self.dependencies[d][0], opt
1526
# depend, desc, required_for_opt, opt
1528
# opt. deps in req. options
1529
for opt in self.components[self.selected_component][1]:
1530
if self.options[opt][0]: # required options
1531
for d in self.options[opt][2]: # dependencies for option
1533
status, output = self.run('cups-config --version')
1535
if status == 0 and (string.count(output, '.') == 1 or string.count(output, '.') == 2):
1536
if string.count(output, '.') == 1:
1537
major, minor = string.split(output, '.', 2)
1538
if string.count(output, '.') == 2:
1539
major, minor, release = string.split(output, '.', 3)
1540
if len(minor) > 1 and minor[1] >= '0' and minor[1] <= '9':
1541
minor = ((ord(minor[0]) - ord('0')) * 10) + (ord(minor[1]) - ord('0'))
1543
minor = ord(minor[0]) - ord('0')
1544
if major > '1' or (major == '1' and minor >= 4):
1546
if not self.dependencies[d][0]: # optional dep
1547
if not self.have_dependencies[d]: # missing
1548
log.debug("Missing optional dependency: %s" % d)
1549
yield d, self.dependencies[d][2], self.dependencies[d][0], opt
1550
# depend, desc, option
1552
def select_options(self, answer_callback):
1554
# not-required options
1555
for opt in self.components[self.selected_component][1]:
1556
if not self.options[opt][0]: # not required
1559
if not self.selected_options[opt]:
1562
self.selected_options[opt] = answer_callback(opt, self.options[opt][1], default)
1564
if self.selected_options[opt]: # only for options that are ON
1565
for d in self.options[opt][2]: # dependencies
1566
if not self.have_dependencies[d]: # missing dependency
1567
log.debug("Missing optional dependency: %s" % d)
1568
num_opt_missing += 1
1570
return num_opt_missing
1573
def check_network_connection(self):
1574
self.network_connected = False
1576
wget = utils.which("wget")
1578
wget = os.path.join(wget, "wget")
1579
cmd = "%s --timeout=60 --output-document=- %s" % (wget, HTTP_GET_TARGET)
1581
status, output = self.run(cmd)
1582
log.debug("wget returned: %d" % status)
1583
self.network_connected = (status == 0)
1586
curl = utils.which("curl")
1588
curl = os.path.join(curl, "curl")
1589
cmd = "%s --output - --connect-timeout 5 --max-time 10 %s" % (curl, HTTP_GET_TARGET)
1591
status, output = self.run(cmd)
1592
log.debug("curl returned: %d" % status)
1593
self.network_connected = (status == 0)
1596
ping = utils.which("ping")
1599
ping = os.path.join(ping, "ping")
1600
cmd = "%s -c1 -W1 -w10 %s" % (ping, PING_TARGET)
1602
status, output = self.run(cmd)
1603
log.debug("ping returned: %d" % status)
1604
self.network_connected = (status == 0)
1606
return self.network_connected
1609
def run_pre_install(self, callback=None):
1610
pre_cmd = self.get_distro_ver_data('pre_install_cmd')
1615
status, output = self.run(cmd)
1618
log.warn("An error occurred running '%s'" % cmd)
1620
if callback is not None:
1621
callback(cmd, "Pre-install step %d" % x)
1631
def run_pre_depend(self, callback=None):
1632
pre_cmd = self.get_distro_ver_data('pre_depend_cmd')
1637
status, output = self.run(cmd)
1640
log.warn("An error occurred running '%s'" % cmd)
1642
if callback is not None:
1643
callback(cmd, "Pre-depend step %d" % x)
1648
def run_post_depend(self, callback=None):
1649
post_cmd = self.get_distro_ver_data('post_depend_cmd')
1653
for cmd in post_cmd:
1654
status, output = self.run(cmd)
1657
log.warn("An error occurred running '%s'" % cmd)
1659
if callback is not None:
1660
callback(cmd, "Post-depend step %d" % x)
1665
def run_open_mdns_port(self, callback=None):
1666
open_mdns_port_cmd = self.get_distro_ver_data('open_mdns_port')
1667
log.debug(open_mdns_port_cmd)
1668
if open_mdns_port_cmd:
1670
for cmd in open_mdns_port_cmd:
1671
cmd = self.su_sudo() % cmd
1672
status, output = self.run(cmd)
1675
log.warn("An error occurred running '%s'" % cmd)
1678
if callback is not None:
1679
callback(cmd, "Open mDNS/Bonjour step %d" % x)
1684
def pre_build(self):
1686
if self.get_distro_ver_data('fix_ppd_symlink', False):
1687
cmds.append(self.su_sudo() % 'python ./installer/fix_symlink.py')
1692
def run_pre_build(self, callback=None):
1694
for cmd in self.pre_build():
1695
status, output = self.run(cmd)
1696
if callback is not None:
1697
callback(cmd, "Pre-build step %d" % x)
1702
def run_post_build(self, callback=None):
1704
for cmd in self.post_build():
1705
status, output = self.run(cmd)
1706
if callback is not None:
1707
callback(cmd, "Post-build step %d" % x)
1712
def post_build(self):
1714
# Reload DBUS configuration if distro supports it and PolicyKit
1716
if self.reload_dbus and self.selected_options['policykit']:
1717
cmds.append(self.su_sudo() % "sh /etc/init.d/dbus reload")
1718
log.debug("Will reload DBUS configuration for PolicyKit support")
1720
# Kill any running hpssd.py instance from a previous install
1721
if self.check_hpssd():
1722
pid = get_ps_pid('hpssd')
1724
kill = os.path.join(utils.which("kill"), "kill") + " %d" % pid
1725
cmds.append(self.su_sudo() % kill)
1727
# Add user to group if needed
1728
# add_user_to_group=<usermod params> [TYPE_STRING] (leave empty for none) [ex. "-a -G sys" or "-G lp"]
1729
add_user_to_group = self.get_distro_ver_data('add_user_to_group', '')
1730
if add_user_to_group:
1731
usermod = os.path.join(utils.which("usermod"), "usermod") + " %s %s" % (add_user_to_group, prop.username)
1732
cmds.append(self.su_sudo() % usermod)
1739
pkill = utils.which('pkill')
1741
cmd = "%s -KILL -u %s" % (os.path.join(pkill, "pkill"), prop.username)
1742
cmd = self.su_sudo() % cmd
1743
status, output = self.run(cmd)
1752
shutdown = utils.which('shutdown')
1754
cmd = "%s -r now" % (os.path.join(shutdown, "shutdown"))
1755
cmd = self.su_sudo() % cmd
1756
status, output = self.run(cmd)
1763
def run_hp_setup(self):
1765
hpsetup = utils.which("hp-setup")
1773
status, output = self.run(cmd)
1777
def remove_hplip(self, callback=None):
1779
self.stop_pre_2x_hplip(callback)
1781
hplip_remove_cmd = self.get_distro_data('hplip_remove_cmd')
1782
if hplip_remove_cmd:
1783
if callback is not None:
1784
callback(hplip_remove_cmd, "Removing old HPLIP version")
1786
status, output = self.run(hplip_remove_cmd)
1789
self.hplip_present = self.check_hplip()
1791
if not self.hplip_present:
1797
def stop_pre_2x_hplip(self, callback=None):
1798
hplip_init_script = '/etc/init.d/hplip stop'
1799
if os.path.exists(hplip_init_script):
1800
cmd = self.su_sudo() % hplip_init_script
1802
if callback is not None:
1803
callback(cmd, "Stopping old HPLIP version.")
1805
status, output = self.run(cmd)
1809
def check_password(self, password_entry_callback, callback=None):
1810
self.clear_su_sudo_password()
1813
self.password = password_entry_callback()
1814
cmd = self.su_sudo() % "true"
1818
status, output = self.run(cmd)
1824
if callback is not None:
1825
callback("", "Password accepted")
1828
if callback is not None:
1829
if "not in the sudoers file" in output:
1830
callback("", "%s is not in the sudoers file. Check privileges\n" %(os.getenv('USER')) )
1833
callback("", "Password incorrect. %d attempt(s) left." % (3-x ))
1842
def clear_su_sudo_password(self):
1843
if self.su_sudo_str() == 'sudo':
1844
log.debug("Clearing password...")
1851
def set_plugin_version(self):
1852
self.plugin_version = prop.installed_version
1853
log.debug("Plug-in version=%s" % self.plugin_version)
1854
self.plugin_name = 'hplip-%s-plugin.run' % self.plugin_version
1855
log.debug("Plug-in=%s" % self.plugin_name)
1858
def get_plugin_conf_url(self):
1859
url = "http://hplip.sf.net/plugin.conf"
1860
home = sys_conf.get('dirs', 'home')
1862
if os.path.exists('/etc/hp/plugin.conf'):
1863
url = "file:///etc/hp/plugin.conf"
1865
elif os.path.exists(os.path.join(home, 'plugin.conf')):
1866
url = "file://" + os.path.join(home, 'plugin.conf')
1868
log.debug("Plugin.conf url: %s" % url)
1872
def get_plugin_info(self, plugin_conf_url, callback):
1873
ok, size, checksum, timestamp, url = False, 0, 0, 0.0, ''
1875
if not self.create_plugin_dir():
1876
log.error("Could not create plug-in directory.")
1877
return '', 0, 0, 0, False
1879
local_conf_fp, local_conf = utils.make_temp_file()
1881
#if os.path.exists(local_conf):
1882
#os.remove(local_conf)
1886
#filename, headers = urllib.urlretrieve(plugin_conf_url, local_conf, callback)
1887
wget = utils.which("wget")
1889
wget = os.path.join(wget, "wget")
1890
status, output = self.run("%s --timeout=60 --output-document=%s %s --cache=off" %(wget, local_conf, plugin_conf_url))
1892
log.error("Plugin download failed with error code = %d" %status)
1893
return '', 0, 0, 0, False
1895
log.error("Please install wget package to download the plugin.")
1896
return '', 0, 0, 0, False
1898
log.error("I/O Error: %s" % e.strerror)
1899
return '', 0, 0, 0, False
1901
if not os.path.exists(local_conf):
1902
log.error("plugin.conf not found.")
1903
return '', 0, 0, 0, False
1905
plugin_conf_p = ConfigParser.ConfigParser()
1908
plugin_conf_p.read(local_conf)
1909
except (ConfigParser.MissingSectionHeaderError, ConfigParser.ParsingError):
1910
log.error("Error parsing file - 404 error?")
1911
return '', 0, 0, 0, False
1914
url = plugin_conf_p.get(self.plugin_version, 'url')
1915
size = plugin_conf_p.getint(self.plugin_version, 'size')
1916
checksum = plugin_conf_p.get(self.plugin_version, 'checksum')
1917
timestamp = plugin_conf_p.getfloat(self.plugin_version, 'timestamp')
1919
except (KeyError, ConfigParser.NoSectionError):
1920
log.error("Error reading plugin.conf: Missing section [%s]" % self.plugin_version)
1921
return '', 0, 0, 0, False
1924
os.close(local_conf_fp)
1925
os.remove(local_conf)
1927
return url, size, checksum, timestamp, ok
1930
def create_plugin_dir(self):
1931
if not os.path.exists(self.plugin_path):
1933
log.debug("Creating plugin directory: %s" % self.plugin_path)
1935
os.makedirs(self.plugin_path, 0755)
1937
except (OSError, IOError), e:
1938
log.error("Unable to create directory: %s" % e.strerror)
1944
def isErrorPage(self, page):
1946
Example code from David Mertz' Text Processing in Python.
1947
Released in the Public Domain.
1951
for pat, prob in err_pats.items():
1952
if err_score > 0.9: break
1953
if re.search(pat, page):
1956
log.debug("File error page score: %f" % (err_score))
1958
return err_score > 0.50
1961
def download_plugin(self, url, size, checksum, timestamp, callback=None):
1962
log.debug("Downloading %s plug-in file from '%s' to '%s'..." % (self.plugin_version, url, self.plugin_path))
1964
if not self.create_plugin_dir():
1965
return PLUGIN_INSTALL_ERROR_DIRECTORY_ERROR, self.plugin_path
1967
plugin_file = os.path.join(self.plugin_path, self.plugin_name)
1970
#Check whether plugin is accessible in Openprinting.org website otherwise dowload plugin from alternate location.
1971
wget = utils.which("wget")
1973
wget = os.path.join(wget, "wget")
1974
cmd = "%s --cache=off -P %s %s" % (wget,self.plugin_path,url)
1976
status, output = self.run(cmd)
1977
log.debug("wget returned: %d" % status)
1980
if (status != 0) and 'file://' not in url:
1981
url = os.path.join(PLUGIN_FALLBACK_LOCATION, self.plugin_name)
1982
log.info("Plugin is not accessible. Trying to download it from fallback location: [%s]" % url)
1983
cmd = "%s --cache=off -P %s %s" % (wget,self.plugin_path,url)
1985
status, output = self.run(cmd)
1986
if 'file://' in url:
1987
filename, headers = urllib.urlretrieve(url, plugin_file, callback)
1989
log.error("Plug-in download failed: %s" % e.strerror)
1990
return PLUGIN_INSTALL_ERROR_PLUGIN_FILE_NOT_FOUND, e.strerror
1992
if self.isErrorPage(file(plugin_file, 'r').read(1024)):
1993
log.debug(file(plugin_file, 'r').read(1024))
1994
os.remove(plugin_file)
1995
return PLUGIN_INSTALL_ERROR_PLUGIN_FILE_NOT_FOUND, -1
1997
calc_checksum = get_checksum(file(plugin_file, 'r').read())
1998
log.debug("D/L file checksum=%s" % calc_checksum)
2000
# Try to download and check the GPG digital signature
2001
digsig_url = url + '.asc'
2002
digsig_file = plugin_file + '.asc'
2004
log.debug("Downloading %s plug-in digital signature file from '%s' to '%s'..." % (self.plugin_version, digsig_url, digsig_file))
2007
if 'file://' in url:
2008
filename, headers = urllib.urlretrieve(digsig_url, digsig_file, callback)
2010
cmd = "%s --cache=off -P %s %s" % (wget,self.plugin_path,digsig_url)
2012
status, output = self.run(cmd)
2014
log.error("Plug-in GPG file [%s] download failed: %s" % (digsig_url,e.strerror))
2015
return PLUGIN_INSTALL_ERROR_DIGITAL_SIG_NOT_FOUND, e.strerror
2017
if self.isErrorPage(file(digsig_file, 'r').read(1024)):
2018
log.debug(file(digsig_file, 'r').read())
2019
os.remove(digsig_file)
2020
return PLUGIN_INSTALL_ERROR_DIGITAL_SIG_NOT_FOUND, -1
2022
gpg = utils.which('gpg')
2024
gpg = os.path.join(gpg, 'gpg')
2025
cmd = '%s --no-permission-warning --keyserver pgp.mit.edu --recv-keys 0xA59047B9' % gpg
2026
log.info("Receiving digital keys: %s" % cmd)
2027
status, output = self.run(cmd)
2031
return PLUGIN_INSTALL_ERROR_UNABLE_TO_RECV_KEYS, status
2033
cmd = '%s --no-permission-warning --verify %s %s' % (gpg, digsig_file, plugin_file)
2034
log.debug("Verifying plugin with digital keys: %s" % cmd)
2035
status, output = self.run(cmd)
2037
log.debug("%s status: %d" % (gpg, status))
2040
return PLUGIN_INSTALL_ERROR_DIGITAL_SIG_BAD, status
2043
return PLUGIN_INSTALL_ERROR_NONE, plugin_file
2047
# '-1' --> PLUGIN_VERSION_MISMATCH -->version mismatch
2048
# '0' --> PLUGIN_NOT_INSTALLED --> not installed
2049
# '1' --> PLUGIN_INSTALLED
2051
def check_for_plugin(self):
2053
plugin_state = sys_state.get('plugin', 'installed', PLUGIN_NOT_INSTALLED)
2054
if plugin_state != PLUGIN_NOT_INSTALLED and self.check_plugin_version() is False:
2055
log.debug("Plug-in version mismatch. Need to install plugin again")
2056
plugin_state = PLUGIN_VERSION_MISMATCH
2057
elif plugin_state == PLUGIN_INSTALLED:
2058
log.debug("Plugin is installed")
2060
log.debug("Plugin is not installed")
2062
# cross checking so files present or not.
2063
if plugin_state != PLUGIN_NOT_INSTALLED:
2064
Scan_sts =self.check_scanner_plugin_files()
2065
Fax_sts = self.check_fax_plugin_files()
2066
Prnt_sts = self.check_printer_plugin_files()
2067
if Scan_sts!= PLUGIN_STATUS_FILES_PRESENT or Fax_sts!= PLUGIN_STATUS_FILES_PRESENT or Prnt_sts != PLUGIN_STATUS_FILES_PRESENT:
2068
log.debug("Plug-in files might be corrupted. Re-install plug-in")
2069
plugin_state = PLUGIN_VERSION_MISMATCH
2073
def check_plugin_version(self):
2075
plugin_installed_version = sys_state.get('plugin','version', '0.0.0')
2076
hplip_version = sys_conf.get('hplip', 'version', '0.0.0')
2077
if plugin_installed_version == hplip_version:
2084
def check_printer_plugin_files(self):
2086
home = sys_conf.get('dirs', 'home')
2087
printer_so_dir= home+"/prnt/plugins/"
2088
ret_val = self.check_so_exists(printer_so_dir, 'lj.so', "Printer",ret_val)
2092
def check_scanner_plugin_files(self):
2094
home = sys_conf.get('dirs', 'home')
2095
scan_so_files_list =['bb_marvell.so' , 'bb_soapht.so' , 'bb_soap.so']
2098
scanner_so_dir= home+'/scan/plugins/'
2099
while cnt < len(scan_so_files_list):
2100
ret_val = self.check_so_exists(scanner_so_dir, scan_so_files_list[cnt], "Scanner",ret_val)
2106
def check_fax_plugin_files(self):
2108
home = sys_conf.get('dirs', 'home')
2109
fax_so_dir= home+"/fax/plugins/"
2110
ret_val = self.check_so_exists(fax_so_dir,'fax_marvell.so' ,"Fax",ret_val)
2114
def check_so_exists(self, sym_link_dir, so_file, functionType, Pre_ret_val):
2115
ret_val = Pre_ret_val
2116
sym_link_file = sym_link_dir + so_file
2117
if not os.path.exists(sym_link_file):
2118
log.debug("Either %s file is not present or symbolic link is missing: %s" %(functionType, sym_link_file))
2119
user_conf.set(functionType+'_plugins', so_file,'Not_Found')
2121
ret_val= PLUGIN_STATUS_FILES_NOT_PRESENT
2122
elif ret_val == PLUGIN_STATUS_FILES_PRESENT:
2123
ret_val = PLUGIN_STATUS_PARTIAL_FILES_PRESENT
2125
# capturing real file path
2126
if os.path.islink(sym_link_file):
2127
real_file = os.path.realpath(sym_link_file)
2129
real_file = sym_link_file
2131
if not os.path.exists(real_file):
2132
log.debug("%s Plugin file is missing: %s" % (functionType, real_file))
2133
user_conf.set(functionType+'_plugins', so_file,'Not_Found')
2135
ret_val= PLUGIN_STATUS_FILES_NOT_PRESENT
2136
elif ret_val == PLUGIN_STATUS_FILES_PRESENT:
2137
ret_val = PLUGIN_STATUS_PARTIAL_FILES_PRESENT
2138
elif (os.stat(sym_link_file).st_mode & 72) != 72:
2139
user_conf.set(functionType+'_plugins', so_file,'Permissin_Error')
2140
log.debug("%s Plugin file doesn't have user/group execute permission: %s" % (functionType,sym_link_file))
2142
ret_val= PLUGIN_STATUS_FILES_NOT_PRESENT
2143
elif ret_val == PLUGIN_STATUS_FILES_PRESENT:
2144
ret_val = PLUGIN_STATUS_PARTIAL_FILES_PRESENT
2146
user_conf.set(functionType+'_plugins', so_file,'Present')
2148
ret_val= PLUGIN_STATUS_FILES_PRESENT
2149
elif ret_val == PLUGIN_STATUS_FILES_NOT_PRESENT:
2150
ret_val = PLUGIN_STATUS_PARTIAL_FILES_PRESENT
2152
log.debug("%s Plug-in file %s status: %d" % (functionType, sym_link_file, ret_val))
2157
def run_plugin(self, mode=GUI_MODE, callback=None):
2158
plugin_file = os.path.join(self.plugin_path, self.plugin_name)
2160
if not os.path.exists(plugin_file):
2163
if mode == GUI_MODE:
2164
return os.system("sh %s --nox11 -- -u" % plugin_file) == 0
2166
if os.system("sh %s --nox11 -- -i" % plugin_file) == 0:
2169
log.error("Python gobject/dbus may be not installed")
2173
def delete_plugin(self):
2174
plugin_file = os.path.join(self.plugin_path, self.plugin_name)
2175
digsig_file = plugin_file + ".asc"
2177
if os.path.exists(plugin_file):
2178
os.unlink(plugin_file)
2179
if os.path.exists(digsig_file):
2180
os.unlink(digsig_file)
2183
def is_auto_installer_support(self):
2184
if not self.distro_name:
2186
self.distro_name = self.distros_index[self.distro]
2188
if self.distro_name and self.distro_name in ("ubuntu","debian","suse","fedora"):
2189
log.debug("Auto installation is supported for Distro =%s version =%s "%(self.distro_name, self.distro_version))
2192
log.debug("Auto installation is not supported for Distro =%s version =%s "%(self.distro_name, self.distro_version))
2196
def uninstall(self,mode = INTERACTIVE_MODE, callback=None):
2198
if os.getuid() != 0:
2200
# log.error("To run 'hp-uninstall' utility, you must have root privileges.")
2203
home_dir= sys_conf.get("dirs","home","")
2204
version= sys_conf.get("hplip","version","0.0.0")
2206
log.error("HPLIP is not installed.")
2209
if mode != NON_INTERACTIVE_MODE:
2210
ok,choice = tui.enter_choice("\nAre you sure to uninstall HPLIP-%s (y=yes, n=no*)?:" %version,['y','n'],'n')
2211
if not ok or choice == 'n':
2214
hplip_remove_cmd = self.get_distro_data('hplip_remove_cmd')
2215
log.debug("hplip_remove_cmd =%s "%hplip_remove_cmd)
2216
#read conf file to enter into installed dir
2217
log.info("Starting uninstallation...")
2219
plugin_state = sys_state.get('plugin', 'installed', PLUGIN_NOT_INSTALLED)
2221
# check systray is running?
2222
status,output = utils.Is_Process_Running('hp-systray')
2224
if mode != NON_INTERACTIVE_MODE:
2225
ok,choice = tui.enter_choice("\nSome HPLIP applications are running. Press 'y' to close and proceed or Press 'n' to quit uninstall (y=yes*, n=no):",['y','n'],'y')
2226
if not ok or choice =='n':
2227
log.info("Quiting HPLIP unininstallation. Close application(s) manually and run again.")
2231
from dbus import SystemBus, lowlevel
2233
log.error("Unable to load DBus")
2237
args = ['', '', EVENT_SYSTEMTRAY_EXIT, prop.username, 0, '', '']
2238
msg = lowlevel.SignalMessage('/', 'com.hplip.StatusService', 'Event')
2239
msg.append(signature='ssisiss', *args)
2240
log.debug("Sending close message to hp-systray ...")
2241
SystemBus().send_message(msg)
2244
log.error("Failed to send DBus message to hp-systray/hp-toolbox.")
2248
toolbox_status,output = utils.Is_Process_Running('hp-toolbox')
2249
systray_status,output = utils.Is_Process_Running('hp-systray')
2250
if toolbox_status is True or systray_status is True:
2251
log.error("Failed to close HP-Toolbox/HP-Systray. Close manually and run hp-uninstall again.")
2254
if hplip_remove_cmd:
2255
self.remove_hplip(callback)
2257
#removing .hplip directory
2258
cmd='find /home -name .hplip'
2260
cmd= self.su_sudo() %cmd
2262
status, output=self.run(cmd)
2263
if output is not None:
2264
for p in output.splitlines():
2265
if p.find("find:") != -1:
2268
cmd= RMDIR + " " + p
2270
cmd= self.su_sudo() %cmd
2271
log.debug("Removing .hplip folder cmd = %s " %cmd)
2272
status, output=self.run(cmd)
2274
log.debug("Failed to remove directory=%s "%p)
2276
#remove the binaries and libraries
2277
pat=re.compile(r"""(.*)share\/hplip""")
2278
base =pat.match(home_dir)
2280
if base is not None:
2281
usrbin_dir= base.group(1) + "bin/"
2282
usrlib_dir= base.group(1) + "lib/"
2284
while cnt <len (BINS_LIST ):
2285
cmd = RM + " " + usrbin_dir + BINS_LIST[cnt]
2287
cmd= self.su_sudo() %cmd
2289
log.debug("Removing binaries cmd = %s " %cmd)
2290
status, output=self.run(cmd)
2292
log.debug("Failed to remove '%s' binary." %(usrbin_dir + BINS_LIST[cnt]))
2296
while cnt <len (LIBS_LIST ):
2297
cmd = RM + " " + usrlib_dir + LIBS_LIST[cnt]
2299
cmd= self.su_sudo() %cmd
2301
log.debug("Removing library cmd = %s " %cmd)
2302
status, output=self.run(cmd)
2304
log.debug("Failed to remove '%s' library." %(usrlib_dir + LIBS_LIST[cnt]))
2308
remove_plugins = False
2309
if mode != NON_INTERACTIVE_MODE and plugin_state != PLUGIN_NOT_INSTALLED:
2310
ok,choice = tui.enter_choice("\nDo you want to remove HP proprietary plug-ins (y=yes*, n=no)?:",['y','n'],'y')
2311
if ok and choice =='y':
2312
remove_plugins = True
2314
remove_plugins = True
2316
# removing HPLIP installed directories/files
2318
while cnt < len(HPLIP_LIST):
2319
cmd=RMDIR + " " + home_dir+"/"+HPLIP_LIST[cnt]
2321
cmd= self.su_sudo() %cmd
2323
log.debug("Removing hplip directory/file cmd= %s " %cmd)
2324
status, output=self.run(cmd)
2326
log.debug("Failed to remove hplip directory/file=%s "% (home_dir+"/"+HPLIP_LIST[cnt]))
2329
# removing configuration files
2331
while cnt < len(FILES_LIST):
2332
cmd = RMDIR + " " + FILES_LIST[cnt]
2334
cmd= self.su_sudo() %cmd
2335
log.debug("Removing conf files cmd= %s" %(cmd))
2336
status, output=self.run(cmd)
2338
log.debug("Failed to remove '%s' file" %FILES_LIST[cnt])
2340
# removing Plug-in files
2341
if remove_plugins == True:
2343
while cnt < len(PLUGIN_LIST):
2344
cmd=RMDIR + " " + home_dir+"/"+PLUGIN_LIST[cnt]
2346
cmd= self.su_sudo() %cmd
2348
log.debug("Removing hplip Plug-in files cmd= %s " %cmd)
2349
status, output=self.run(cmd)
2351
log.debug("Failed to remove plug-in directory/file=%s "% (home_dir+"/"+PLUGIN_LIST[cnt]))
2355
while cnt < len(PLUGIN_STATE):
2356
cmd=RMDIR + " "+PLUGIN_STATE[cnt]
2358
cmd= self.su_sudo() %cmd
2360
log.debug("Removing hplip Plug-in file cmd= %s " %cmd)
2361
status, output=self.run(cmd)
2363
log.debug("Failed to remove plug-in directory/file=%s "% (PLUGIN_STATE[cnt]))
2366
cmd =RMDIR+ " "+home_dir
2368
cmd= self.su_sudo() %cmd
2370
log.debug("Removing hplip directory/file cmd= %s " %cmd)
2371
status, output=self.run(cmd)
2373
log.debug("Failed to remove hplip directory=%s "% (home_dir))
2375
# removing HPLIP uninstall link
2376
if usrbin_dir is not None:
2377
cmd=RMDIR + " " + usrbin_dir+"hp-uninstall"
2379
cmd= self.su_sudo() %cmd
2381
log.debug("Removing hplip binary cmd= %s " %cmd)
2382
status, output=self.run(cmd)
2384
log.debug("Failed to remove '%s' file" %(usrbin_dir+"hp-uninstall"))
2385
log.info("HPLIP uninstallation is completed")