Tizen 2.1 base
[platform/upstream/hplip.git] / installer / text_install.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # (c) Copyright 2003-2014 Hewlett-Packard Development Company, L.P.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 #
20 # Author: Don Welch, Amarnath Chitumalla
21 #
22
23 # Std Lib
24 import os
25 import sys
26 import getpass
27 import signal
28
29 # Local
30 from base.g import *
31 from base import utils, tui
32 from core_install import *
33
34 def start_systray():
35     tui.title("RE-STARTING HP_SYSTRAY")
36     path = utils.which('hp-systray')
37     if path:
38         path = os.path.join(path, 'hp-systray')
39     else:
40         path = os.path.join(prop.home_dir, 'systray.py')
41     if not os.path.exists(path):
42         log.warn("Unable to start hp-systray")
43
44     log.debug("Running hp-systray: %s --force-startup" % path)
45     os.spawnlp(os.P_NOWAIT, path, 'hp-systray', '--force-startup')
46     log.debug("Waiting for hp-systray to start...")
47     time.sleep(1)
48
49
50 def progress_callback(cmd="", desc="Working..."):
51     if cmd:
52         log.info("%s (%s)" % (cmd, desc))
53     else:
54         log.info(desc)
55
56
57 def password_entry():
58     return getpass.getpass(log.bold("Please enter the root/superuser password: "))
59
60 def password_user_entry():
61     return getpass.getpass(log.bold("Please enter the user (%s)'s password: " % os.getenv('USER')))
62
63
64 def option_question_callback(opt, desc, default='y'):
65     ok, ans = tui.enter_yes_no("Do you wish to enable '%s'" % desc, default)
66     if not ok: sys.exit(0)
67     return ans
68
69
70
71 def start(language, auto=True, test_depends=False,
72           test_unknown=False, assume_network=False,
73           max_retries=3, enable=None, disable=None):
74     try:
75         core =  CoreInstall(MODE_INSTALLER, INTERACTIVE_MODE)
76         current_version = prop.installed_version_int
77         log.debug("Currently installed version: 0x%06x" % current_version)
78         core.enable = enable
79         core.disable = disable
80
81         if core.running_as_root():
82             log.error("You are running the installer as root. It is highly recommended that you run the installer as")
83             log.error("a regular (non-root) user. Do you still wish to continue?")
84
85             ok, ans = tui.enter_yes_no(log.bold("Continue with installation"), 'n')
86             if not ans or not ok:
87                 sys.exit(1)
88
89         if auto:
90             log.note("Running in automatic mode. The most common options will be selected.")
91
92         log.info("")
93         log.note("Defaults for each question are maked with a '*'. Press <enter> to accept the default.")
94         core.init()
95         if not core.distro_name in ("ubuntu","debian","suse","fedora"):
96             log.error("Auto installation is not supported for '%s' distro so all dependencies may not be installed. \nPlease install manually as mentioned in 'http://hplipopensource.com/hplip-web/install/manual/index.html' web-site"% core.distro_name)
97             ok, choice = tui.enter_choice("\nPress 'y' If you still want to continue auto installation. Press 'n' to quit auto instalation(y=yes, n=no*): ",['y','n'],'n')
98             if not ok or choice =='n':
99                 log.info("Installation exit")
100                 sys.exit()
101
102         if not auto:
103             tui.title("INSTALLATION MODE")
104             log.info("Automatic mode will install the full HPLIP solution with the most common options.")
105             log.info("Custom mode allows you to choose installation options to fit specific requirements.")
106
107             #if os.getenv('DISPLAY') and utils.find_browser() is not None:
108             if 0:
109                 ok, choice = tui.enter_choice("\nPlease choose the installation mode (a=automatic*, c=custom, w=web installer, q=quit) : ",
110                     ['a', 'c', 'w'], 'a')
111             else:
112                 ok, choice = tui.enter_choice("\nPlease choose the installation mode (a=automatic*, c=custom, q=quit) : ",
113                     ['a', 'c'], 'a')
114
115             if not ok: sys.exit(0)
116
117             if choice == 'a':
118                 auto = True
119
120             elif choice == 'w':
121                 import web_install
122                 log.debug("Starting web browser installer...")
123                 web_install.start(language)
124                 return
125
126         log.info("\nInitializing. Please wait...")
127         prev_hplip_version= sys_conf.get("hplip","version","0.0.0")
128
129
130         if test_unknown:
131             core.distro_name = 'unknown'
132             core.distro = 0
133             core.distro_version = 0
134
135
136         #
137         # HPLIP INSTALLATION
138         #
139         core.selected_component = 'hplip'
140
141         #
142         # INTRODUCTION
143         #
144
145         tui.title("INTRODUCTION")
146
147         if core.selected_component == 'hplip':
148             log.info("This installer will install HPLIP version %s on your computer." % core.version_public)
149
150         log.info("Please close any running package management systems now (YaST, Adept, Synaptic, Up2date, etc).")
151
152
153         # For testing, mark all dependencies missing
154         if test_depends:
155             for d in core.have_dependencies:
156                 core.have_dependencies[d] = False
157
158         num_req_missing = core.count_num_required_missing_dependencies()
159         num_opt_missing = core.count_num_optional_missing_dependencies()
160
161
162         #
163         # CONFIRM AND SELECT DISTRO NAME AND VERSION
164         #
165
166         tui.title("DISTRO/OS CONFIRMATION")
167
168
169         if core.distro_known():
170             log.info("Distro appears to be %s %s.\n" % (core.get_distro_data('display_name', '(unknown)'), core.distro_version))
171
172         log.debug("Distro = %s Distro Name = %s Display Name= %s Version = %s Supported = %s" % \
173             (core.distro, core.distro_name, core.distros[core.distro_name]['display_name'], \
174             core.distro_version, core.distro_version_supported))
175
176         distro_ok, ok = False, True
177         if core.distro_known():
178             ok, distro_ok = tui.enter_yes_no('Is "%s %s" your correct distro/OS and version'
179                 % (core.get_distro_data('display_name', '(unknown)'), core.distro_version))
180
181         if not ok:
182             sys.exit(0)
183
184         core.distro_changed()
185
186         if not distro_ok:
187             tui.title("DISTRO/OS SELECTION")
188             core.distro, core.distro_version = DISTRO_UNKNOWN, DISTRO_VER_UNKNOWN
189
190             log.info(log.bold("\nChoose the name of the distro/OS that most closely matches your system:\n"))
191
192             max_name = 0
193             for d in core.distros_index:
194                 dd = core.distros[core.distros_index[d]]
195                 if dd['display']:
196                     max_name = max(max_name, len(dd['display_name']))
197
198             formatter = utils.TextFormatter(
199                     (
200                         {'width': 4},
201                         {'width': max_name, 'margin': 2},
202                     )
203                 )
204
205             log.info(formatter.compose(("Num.", "Distro/OS Name")))
206             log.info(formatter.compose(('-'*4, '-'*(max_name))))
207
208             d_temp = {}
209             x = 0
210             for d in core.distros_index:
211                 dd = core.distros[core.distros_index[d]]
212
213                 if dd['display']:
214                     d_temp[x] = d
215                     log.info(formatter.compose((str(x), dd['display_name'])))
216                     x += 1
217
218             ok, y = tui.enter_range("\nEnter number 0...%d (q=quit) ?" % (x-1), 0, x-1)
219             if not ok: sys.exit(0)
220
221             core.distro = d_temp[y]
222             core.distro_name = core.distros_index[core.distro]
223             distro_display_name = core.distros[core.distro_name]['display_name']
224             log.debug("Distro = %s Distro Name = %s Display Name= %s" %
225                 (core.distro, core.distro_name, distro_display_name))
226
227             if core.distro != DISTRO_UNKNOWN:
228                 versions = core.distros[core.distro_name]['versions'].keys()
229                 versions.sort(lambda x, y: core.sort_vers(x, y))
230
231                 log.info(log.bold('\nChoose the version of "%s" that most closely matches your system:\n' % distro_display_name))
232
233                 formatter = utils.TextFormatter(
234                         (
235                             {'width': 4},
236                             {'width': 40, 'margin': 2},
237                         )
238                     )
239
240                 log.info(formatter.compose(("Num.", "Distro/OS Version")))
241                 log.info(formatter.compose(('-'*4, '-'*40)))
242
243                 log.info(formatter.compose(("0", "Unknown or not listed")))
244
245                 x = 1
246                 for ver in versions:
247                     ver_info = core.distros[core.distro_name]['versions'][ver]
248
249                     if ver_info['code_name'] and ver_info['release_date']:
250                         text = ver + ' ("' + ver_info['code_name'] + '", Released ' + ver_info['release_date'] + ')'
251
252                     elif ver_info['code_name']:
253                         text = ver + ' ("' + ver_info['code_name'] + '")'
254
255                     elif ver_info['release_date']:
256                         text = ver + ' (Released ' + ver_info['release_date'] + ')'
257
258                     else:
259                         text = ver
260
261                     if not ver_info['supported']:
262                         text += " [Unsupported]"
263
264                     log.info(formatter.compose((str(x), text)))
265                     x += 1
266
267                 ok, core.distro_version_int = tui.enter_range("\nEnter number 0...%d (q=quit) ?" %
268                     (x-1), 0, x-1)
269                 if not ok: sys.exit(0)
270
271                 if core.distro_version_int == 0:
272                     core.distro_version = DISTRO_VER_UNKNOWN
273                     core.distro_version_supported = False
274                 else:
275                     core.distro_version = versions[core.distro_version_int - 1]
276                     core.distro_version_supported = core.get_ver_data('supported', False)
277
278                 log.debug("Distro = %s Distro Name = %s Display Name= %s Version = %s Supported = %s" % \
279                     (core.distro, core.distro_name, core.distros[core.distro_name]['display_name'], \
280                     core.distro_version, core.distro_version_supported))
281
282                 core.distro_changed()
283
284                 log.info("\nDistro set to: %s %s" %
285                     (core.get_distro_data('display_name', '(unknown)'), core.distro_version))
286
287
288             if core.distro == DISTRO_UNKNOWN or not core.distro_version_supported:
289                 log.error("The distribution/OS that you are running is not supported. This installer\ncannot install an unsupported distribution. Please check your distribution/OS\nand re-run this installer or perform a manual installation.")
290                 if num_req_missing:
291                     log.error("The following REQUIRED dependencies are missing and need to be installed:")
292
293                     for d, desc, opt in core.missing_required_dependencies():
294                         log.error("Missing REQUIRED dependency: %s (%s)" % (d, desc))
295
296                 for d, desc, req, opt in core.missing_optional_dependencies():
297                     if req:
298                         log.warning("Missing OPTIONAL dependency: %s (%s) [Required for option '%s']" % (d, desc, opt))
299                     else:
300                         log.warning("Missing OPTIONAL dependency: %s (%s) [Optional for option '%s']" % (d, desc, opt))
301
302                 sys.exit(1)
303
304
305         #
306         # SELECT OPTIONS TO INSTALL
307         #
308
309         if not auto:
310             tui.title("SELECT HPLIP OPTIONS")
311             log.info("You can select which HPLIP options to enable. Some options require extra dependencies.")
312             log.info("")
313             num_opt_missing = core.select_options(option_question_callback)
314
315         else:
316             enable_par = False
317             core.selected_options['parallel'] = False
318
319         log.debug("Req missing=%d Opt missing=%d HPLIP=%s Component=%s" % \
320             (num_req_missing, num_opt_missing, core.hplip_present, core.selected_component))
321
322
323         #
324         # COLLECT SUPERUSER PASSWORD
325         #
326         if not core.running_as_root():
327             su_sudo = core.get_distro_data('su_sudo')
328             if su_sudo == "sudo":
329                 tui.title("ENTER USER PASSWORD")
330                 ok = core.check_password(password_user_entry, progress_callback)
331             else:
332                 tui.title("ENTER ROOT/SUPERUSER PASSWORD")
333                 ok = core.check_password(password_entry, progress_callback)
334
335             if not ok:
336                 log.error("3 incorrect attempts. (or) Insufficient permissions(i.e. try with sudo user).\nExiting.")
337                 sys.exit(1)
338
339
340         # INSTALLATION NOTES
341         #
342
343         if core.distro_supported():
344             distro_notes = core.get_distro_data('notes', '').strip()
345             ver_notes = core.get_ver_data('notes', '').strip()
346
347             if distro_notes or ver_notes:
348                 tui.title("INSTALLATION NOTES")
349
350                 if distro_notes:
351                     log.info(distro_notes)
352
353                 if ver_notes:
354                     log.info(ver_notes)
355
356                 log.info("")
357
358                 if not tui.continue_prompt("Please read the installation notes."):
359                     sys.exit(0)
360
361         #
362         # PRE-INSTALL COMMANDS
363         #
364         tui.title("RUNNING PRE-INSTALL COMMANDS")
365         if core.run_pre_install(progress_callback): # some cmds were run...
366             num_req_missing = core.count_num_required_missing_dependencies()
367             num_opt_missing = core.count_num_optional_missing_dependencies()
368         log.info("OK")
369
370         #
371         # REQUIRED DEPENDENCIES INSTALL
372         #
373
374         depends_to_install = []
375         if num_req_missing:
376             tui.title("INSTALL MISSING REQUIRED DEPENDENCIES")
377
378             log.warn("There are %d missing REQUIRED dependencies." % num_req_missing)
379             log.notice("Installation of dependencies requires an active internet connection.")
380
381             for depend, desc, option in core.missing_required_dependencies():
382                 log.warning("Missing REQUIRED dependency: %s (%s)" % (depend, desc))
383
384                 ok = False
385                 packages, commands = core.get_dependency_data(depend)
386                 log.debug("Packages: %s" % ','.join(packages))
387                 log.debug("Commands: %s" % ','.join(commands))
388
389                 if core.distro_version_supported and (packages or commands):
390                     if auto:
391                         answer = True
392                     else:
393                         ok, answer = tui.enter_yes_no("\nWould you like to have this installer install the missing dependency")
394                         if not ok: sys.exit(0)
395
396                     if answer:
397                         ok = True
398                         log.debug("Adding '%s' to list of dependencies to install." % depend)
399                         depends_to_install.append(depend)
400
401                 else:
402                     log.warn("This installer cannot install '%s' for your distro/OS and/or version." % depend)
403
404                 if not ok:
405                     log.error("Installation cannot continue without this dependency. Please manually install this dependency and re-run this installer.")
406                     sys.exit(0)
407
408         #
409         # OPTIONAL dependencies
410         #
411
412         if num_opt_missing:
413             tui.title("INSTALL MISSING OPTIONAL DEPENDENCIES")
414             log.warn("There are %d missing OPTIONAL dependencies." % num_opt_missing)
415
416             log.notice("Installation of dependencies requires an active internet connection.")
417
418             for depend, desc, required_for_opt, opt in core.missing_optional_dependencies():
419
420                 if required_for_opt:
421                     log.warning("Missing REQUIRED dependency for option '%s': %s (%s)" % (opt, depend, desc))
422
423                 else:
424                     log.warning("Missing OPTIONAL dependency for option '%s': %s (%s)" % (opt, depend, desc))
425
426                 installed = False
427                 packages, commands = core.get_dependency_data(depend)
428                 log.debug("Packages: %s" % ','.join(packages))
429                 log.debug("Commands: %s" % ','.join(commands))
430
431
432                 if core.distro_version_supported and (packages or commands):
433                     if auto:
434                         answer = True
435                     else:
436                         ok, answer = tui.enter_yes_no("\nWould you like to have this installer install the missing dependency")
437                         if not ok: sys.exit(0)
438
439                     if answer:
440                         log.debug("Adding '%s' to list of dependencies to install." % depend)
441                         depends_to_install.append(depend)
442
443                     else:
444                         log.warning("Missing dependencies may effect the proper functioning of HPLIP. Please manually install this dependency after you exit this installer.")
445                         log.warning("Note: Options that have REQUIRED dependencies that are missing will be turned off.")
446
447                         if required_for_opt:
448                             log.warn("Option '%s' has been turned off." % opt)
449                             core.selected_options[opt] = False
450                 else:
451                     log.warn("This installer cannot install '%s' for your distro/OS and/or version." % depend)
452
453                     if required_for_opt:
454                         log.warn("Option '%s' has been turned off." % opt)
455                         core.selected_options[opt] = False
456
457
458
459         log.debug("Dependencies to install: %s  hplip_present:%s" % (depends_to_install, core.hplip_present))
460
461         if core.distro_version_supported and \
462             (depends_to_install or core.hplip_present) and \
463             core.selected_component == 'hplip':
464
465             #
466             # CHECK FOR RUNNING PACKAGE MANAGER
467             #
468
469             pid, cmdline = core.check_pkg_mgr()
470             while pid:
471                 ok, user_input = tui.enter_choice("A package manager '%s' appears to be running. Please quit the package manager and press enter to continue (i=ignore, r=retry*, f=force, q=quit) :"
472                     % cmdline, ['i', 'r', 'q', 'f'], 'r')
473
474                 if not ok: sys.exit(0)
475
476                 if user_input == 'i':
477                     log.warn("Ignoring running package manager. Some package operations may fail.")
478                     break
479
480                 if user_input == 'f':
481                     ok, ans = tui.enter_yes_no("\nForce quit of package manager '%s'" % cmdline, 'y')
482
483                     if not ok: sys.exit(0)
484
485                     if ans:
486                         cmd = core.su_sudo() % ("kill %d" % pid)
487                         status, output = core.run(cmd)
488
489                         if status != 0:
490                             log.error("Failed to kill process. You may need to manually quit the program.")
491
492                 pid, cmdline = core.check_pkg_mgr()
493
494
495             #
496             # CHECK FOR ACTIVE NETWORK CONNECTION
497             #
498             if not assume_network:
499                 tui.title("CHECKING FOR NETWORK CONNECTION")
500
501                 if not core.check_network_connection():
502                     log.error("The network appears to be unreachable. Installation may not resolve all dependencies without access to distribution repositories.")
503                     ok, choice = tui.enter_choice("Do you want to continue installation without network?. Press 'y' for YES. Press 'n' for NO (y=yes*, n=no) : ",['y', 'n'], 'y')
504                     if not ok or choice == 'n':
505                         log.info("Please connect network and try again")
506                         sys.exit(1)
507                     else:
508                         log.debug("Continuing installation without network")
509                 else:
510                     log.info("Network connection present.")
511
512             #
513             # PRE-DEPEND
514             #
515
516             tui.title("RUNNING PRE-PACKAGE COMMANDS")
517             core.run_pre_depend(progress_callback)
518             log.info("OK")
519
520             #
521             # INSTALL PACKAGES AND RUN COMMANDS
522             #
523
524             tui.title("DEPENDENCY AND CONFLICT RESOLUTION")
525
526             packages = []
527             commands_to_run = []
528             package_mgr_cmd = core.get_distro_data('package_mgr_cmd')
529
530             # HACK!
531             individual_pkgs = True
532             if package_mgr_cmd.startswith('xterm'):
533                 individual_pkgs = False
534
535             if package_mgr_cmd:
536                 log.debug("Preparing to install packages and run commands...")
537
538                 for d in depends_to_install:
539                     log.debug("*** Processing dependency: %s" % d)
540                     pkgs, commands = core.get_dependency_data(d)
541
542                     if pkgs:
543                         log.debug("Package(s) '%s' will be installed to satisfy dependency '%s'." %
544                             (','.join(pkgs), d))
545
546                         packages.extend(pkgs)
547
548                     if commands:
549                         log.debug("Command(s) '%s' will be run to satisfy dependency '%s'." %
550                             (','.join(commands), d))
551
552                         commands_to_run.extend(commands)
553
554             else:
555                 log.error("Invalid package manager")
556
557             log.debug("Packages: %s" % packages)
558             log.debug("Commands: %s" % commands_to_run)
559             log.debug("Install individual packages: %s" % individual_pkgs)
560
561             if package_mgr_cmd and packages:
562                 if individual_pkgs:
563                     for packages_to_install in packages:
564                         retries = 0
565                         while True:
566                             cmd = utils.cat(package_mgr_cmd)
567                             log.debug("Package manager command: %s" % cmd)
568
569                             log.info("Running '%s'\nPlease wait, this may take several minutes..." % cmd)
570                             status, output = core.run(cmd)
571
572                             if status != 0:
573                                 retries += 1
574                                 if retries < (max_retries+1):
575                                     log.error("Command failed. Re-try #%d..." % retries)
576                                     continue
577
578                                 log.error("Package install command failed with error code %d" % status)
579                                 ok, ans = tui.enter_yes_no("Would you like to retry installing the missing package(s)")
580
581                                 if not ok:
582                                     sys.exit(0)
583
584                                 if ans:
585                                     continue
586                                 else:
587                                     log.warn("Some HPLIP functionality might not function due to missing package(s).")
588                                     break
589                             else:
590                                 break
591
592                 else:
593                     packages_to_install = ' '.join(packages)
594                     while True:
595                         cmd = utils.cat(package_mgr_cmd)
596                         log.debug("Package manager command: %s" % cmd)
597
598                         log.info("Running '%s'\nPlease wait, this may take several minutes..." % cmd)
599                         status, output = core.run(cmd)
600
601                         if status != 0:
602                             log.error("Package install command failed with error code %d" % status)
603                             ok, ans = tui.enter_yes_no("Would you like to retry installing the missing package(s)")
604
605                             if not ok:
606                                 sys.exit(0)
607
608                             if ans:
609                                 continue
610                             else:
611                                 log.warn("Some HPLIP functionality might not function due to missing package(s).")
612                                 break
613                         else:
614                             break
615
616             if commands_to_run:
617                 for cmd in commands_to_run:
618                     log.debug(cmd)
619                     log.info("Running '%s'\nPlease wait, this may take several minutes..." % cmd)
620                     status, output = core.run(cmd)
621
622                     if status != 0:
623                         log.error("Install command failed with error code %d" % status)
624                         sys.exit(1)
625
626
627
628
629             #
630             # HPLIP REMOVE
631             #
632             if core.hplip_present and core.selected_component == 'hplip' and core.distro_version_supported:
633                 path = utils.which('hp-uninstall')
634                 ok, choice = tui.enter_choice("HPLIP-%s exists, this may conflict with the new one being installed.\nDo you want to ('i'= Remove and Install, 'o'= Overwrite*, 'q'= Quit)?      :"%(prev_hplip_version),['i','o','q'],'o')
635                 if not ok or choice=='q':
636                     log.error("User Exit")
637                     sys.exit(0)
638                 elif choice == 'i':
639 #                    log.info("Uninstalling existing HPLIP-%s"%prev_hplip_version)
640                     sts =core.uninstall(NON_INTERACTIVE_MODE)
641
642                     if sts is False: 
643                         log.warn("Failed to uninstall existing HPLIP-%s. This installation will overwrite on existing HPLIP" %prev_hplip_version)
644                     else:
645                         log.debug("HPLIP-%s is uninstalled successfully." %prev_hplip_version)
646
647             #
648             # POST-DEPEND
649             #
650             tui.title("RUNNING POST-PACKAGE COMMANDS")
651             core.run_post_depend(progress_callback)
652             log.info("OK")
653
654
655             #
656             # DEPENDENCIES RE-CHECK
657             #
658             tui.title("RE-CHECKING DEPENDENCIES")
659             core.check_dependencies()
660
661             num_req_missing = 0
662             for depend, desc, opt in core.missing_required_dependencies():
663                 num_req_missing += 1
664                 log.error("A required dependency '%s (%s)' is still missing." % (depend, desc))
665
666             if num_req_missing:
667                 if num_req_missing > 1:
668                     log.error("Installation cannot continue without these dependencies.")
669                 else:
670                     log.error("Installation cannot continue without this dependency.")
671
672                 log.error("Please manually install this dependency and re-run this installer.")
673                 sys.exit(1)
674
675             for depend, desc, required_for_opt, opt in core.missing_optional_dependencies():
676                 if required_for_opt:
677                     log.warn("An optional dependency '%s (%s)' is still missing." % (depend, desc))
678                     log.warn("Option '%s' has been turned off." % opt)
679                     core.selected_options[opt] = False
680                 else:
681                     log.warn("An optional dependency '%s (%s)' is still missing." % (depend, desc))
682                     log.warn("Some features may not function as expected.")
683
684
685             if not num_opt_missing and not num_req_missing:
686                 log.info("OK")
687
688         #
689         # INSTALL LOCATION
690         #
691
692         log.debug("Install location = %s" % core.install_location)
693
694
695         #
696         # BUILD AND INSTALL
697         #
698
699         if not auto:
700             tui.title("READY TO BUILD AND INSTALL")
701             if not tui.continue_prompt("Ready to perform build and install."):
702                 sys.exit(0)
703
704         tui.title("PRE-BUILD COMMANDS")
705         core.run_pre_build(progress_callback)
706         log.info("OK")
707
708         tui.title("BUILD AND INSTALL")
709
710         os.umask(0022)
711         for cmd in core.build_cmds():
712             log.info("Running '%s'\nPlease wait, this may take several minutes..." % cmd)
713             status, output = core.run(cmd)
714
715             if status != 0:
716                 if 'configure' in cmd:
717                     log.error("Configure failed with error: %s" % CONFIGURE_ERRORS.get(status, CONFIGURE_ERRORS[1]))
718
719                 else:
720                     log.error("'%s' command failed with status code %d" % (cmd, status))
721
722                 sys.exit(0)
723             else:
724                 log.info("Command completed successfully.")
725
726             log.info("")
727
728         log.info("\nBuild complete.")
729
730         #
731         # POST BUILD
732         #
733
734         tui.title("POST-BUILD COMMANDS")
735         core.run_post_build(progress_callback)
736
737         #
738         # OPEN MDNS MULTICAST PORT
739         #
740         user_conf = UserConfig()
741         
742         if core.selected_options['network']:
743             open_mdns_port = core.get_distro_ver_data('open_mdns_port')
744             if open_mdns_port:
745                 tui.title("OPEN MDNS/BONJOUR FIREWALL PORT (MULTICAST PORT 5353)")
746
747                 paragraph = "In order to setup your printer on the network using mDNS/Bonjour, it is required that your internet firewall allows connections on port 5353. If this port is blocked by the firewall, connection to network printers using mDNS/Bonjour will not be possible."
748
749                 for p in tui.format_paragraph(paragraph):
750                     log.info(p)
751                 log.info("")
752
753                 ok, ans = tui.enter_yes_no("Do you wish to open this port on your internet firewall")
754                 if not ok: sys.exit(0)
755
756                 if ans:
757                     core.run_open_mdns_port()
758                 else:
759                     log.warn("Skipping firewall setup. If this port is blocked on your firewall when setting up network printers, use SLP discovery and device URIs with ?ip=x.x.x.x. When using hp-setup, choose 'SLP' discovery under 'Advanced'.")
760
761
762         #
763         # Try to close running hp-systray (3.9.2 or later)
764         #
765
766         if current_version >= 0x030902: # 3.9.2
767             try:
768                 from dbus import SessionBus, lowlevel
769             except ImportError:
770                 pass
771             else:
772                 try:
773                     args = ['', '', EVENT_SYSTEMTRAY_EXIT, prop.username, 0, '', '']
774                     msg = lowlevel.SignalMessage('/', 'com.hplip.StatusService', 'Event')
775                     msg.append(signature='ssisiss', *args)
776                     tui.title("CLOSE HP_SYSTRAY")
777                     log.info("Sending close message to hp-systray (if it is currently running)...")
778                     SessionBus().send_message(msg)
779                     time.sleep(0.5)
780                 except:
781                     pass
782         
783         tui.title("HPLIP UPDATE NOTIFICATION")
784         ok, choice = tui.enter_choice("Do you want to check for HPLIP updates?. (y=yes*, n=no) : ",['y', 'n'], 'y')
785         if not ok or choice != 'y':
786             user_conf.set('upgrade', 'notify_upgrade', 'false')
787         else:
788             user_conf.set('upgrade', 'notify_upgrade', 'true')
789
790         user_conf.set('upgrade','last_upgraded_time',str(int(time.time())))
791         user_conf.set('upgrade','pending_upgrade_time','0')
792
793
794         if core.selected_component == 'hplip':
795             tui.title("RESTART OR RE-PLUG IS REQUIRED")
796             cmd = "hp-setup"
797             paragraph = """If you are installing a USB connected printer, and the printer was plugged in when you started this installer, you will need to either restart your PC or unplug and re-plug in your printer (USB cable only). If you choose to restart, run this command after restarting: %s  (Note: If you are using a parallel connection, you will have to restart your PC. If you are using network/wireless, you can ignore and continue).""" % cmd
798
799             for p in tui.format_paragraph(paragraph):
800                 log.info(p)
801             log.info("")
802
803             ok, choice = tui.enter_choice("Restart or re-plug in your printer (r=restart, p=re-plug in*, i=ignore/continue, q=quit) : ",
804                 ['r', 'p', 'i'], 'p')
805
806             if not ok: 
807                 start_systray()
808                 sys.exit(0)
809
810             if choice == 'r':
811                 log.note("")
812                 log.note("IMPORTANT! Make sure to save all work in all open applications before restarting!")
813
814                 ok, ans = tui.enter_yes_no(log.bold("Restart now"), 'n')
815                 if not ok: 
816                     start_systray()
817                     sys.exit(0)
818                 if ans:
819                     ok = core.restart()
820                     if not ok:
821                         log.error("Restart failed. Please restart using the system menu.")
822
823                 start_systray()
824                 sys.exit(0)
825
826             elif choice == 'p': # 'p'
827                 if not tui.continue_prompt("Please unplug and re-plugin your printer now. "):
828                     start_systray()
829                     sys.exit(0)
830
831
832         #
833         # SETUP PRINTER
834         #
835         if core.selected_component == 'hplip':
836             tui.title("PRINTER SETUP")
837
838             if auto:
839                 install_printer = True
840             else:
841                 ok, install_printer = tui.enter_yes_no("Would you like to setup a printer now")
842                 if not ok:
843                     start_systray()
844                     sys.exit(0)
845
846             if install_printer:
847                 log.info("Please make sure your printer is connected and powered on at this time.")
848                 if not core.run_hp_setup():
849                     log.error("hp-setup failed. Please run hp-setup manually.")
850
851         start_systray()
852     except KeyboardInterrupt:
853         log.info("")
854         log.error("Aborted.")
855
856     sys.exit(0)
857