def start(language, auto=True, test_depends=False, test_unknown=False, assume_network=False, max_retries=3, enable=None, disable=None): try: core = CoreInstall(MODE_INSTALLER, INTERACTIVE_MODE) current_version = prop.installed_version_int log.debug("Currently installed version: 0x%06x" % current_version) core.enable = enable core.disable = disable if services.running_as_root(): log.error( "You are running the installer as root. It is highly recommended that you run the installer as" ) log.error( "a regular (non-root) user. Do you still wish to continue?") ok, ans = tui.enter_yes_no(log.bold("Continue with installation"), 'n') if not ans or not ok: sys.exit(1) if auto: log.note( "Running in automatic mode. The most common options will be selected." ) log.info("") log.note( "Defaults for each question are maked with a '*'. Press <enter> to accept the default." ) core.init() vrs = core.get_distro_data('versions_list') Is_Manual_Distro = False distro_alternate_version = None if core.distro_version not in vrs and len(vrs): distro_alternate_version = vrs[len(vrs) - 1] if core.is_auto_installer_support(distro_alternate_version): log.error("%s-%s version is not supported, so all dependencies may not be installed. However trying to install using %s-%s version packages." \ %(core.distro_name, core.distro_version, core.distro_name, distro_alternate_version)) ok, choice = tui.enter_choice( "\nPress 'y' to continue auto installation. Press 'n' to quit auto instalation(y=yes, n=no*): ", ['y', 'n'], 'n') if not ok or choice == 'n': log.info("Installation exit") sys.exit() else: # Even previous distro is not supported Is_Manual_Distro = True elif not core.is_auto_installer_support(): # This distro is not supported Is_Manual_Distro = True if Is_Manual_Distro: 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) ok, choice = tui.enter_choice( "\nPress 'y' to continue auto installation. Press 'n' to quit auto instalation(y=yes, n=no*): ", ['y', 'n'], 'n') if not ok or choice == 'n': log.info("Installation exit") sys.exit() if not auto: tui.title("INSTALLATION MODE") log.info( "Automatic mode will install the full HPLIP solution with the most common options." ) log.info( "Custom mode allows you to choose installation options to fit specific requirements." ) #if os.getenv('DISPLAY') and utils.find_browser() is not None: if 0: ok, choice = tui.enter_choice( "\nPlease choose the installation mode (a=automatic*, c=custom, w=web installer, q=quit) : ", ['a', 'c', 'w'], 'a') else: ok, choice = tui.enter_choice( "\nPlease choose the installation mode (a=automatic*, c=custom, q=quit) : ", ['a', 'c'], 'a') if not ok: sys.exit(0) if choice == 'a': auto = True elif choice == 'w': import web_install log.debug("Starting web browser installer...") web_install.start(language) return log.info("\nInitializing. Please wait...") prev_hplip_version = sys_conf.get("hplip", "version", "0.0.0") pluginObj = pluginhandler.PluginHandle() prev_hplip_plugin_status = pluginObj.getStatus() if test_unknown: core.distro_name = 'unknown' core.distro = 0 core.distro_version = 0 # # HPLIP INSTALLATION # core.selected_component = 'hplip' # # INTRODUCTION # tui.title("INTRODUCTION") if core.selected_component == 'hplip': log.info( "This installer will install HPLIP version %s on your computer." % core.version_public) log.info( "Please close any running package management systems now (YaST, Adept, Synaptic, Up2date, etc)." ) # For testing, mark all dependencies missing if test_depends: for d in core.have_dependencies: core.have_dependencies[d] = False num_req_missing = core.count_num_required_missing_dependencies() num_opt_missing = core.count_num_optional_missing_dependencies() # # CONFIRM AND SELECT DISTRO NAME AND VERSION # tui.title("DISTRO/OS CONFIRMATION") if core.distro_known(): log.info("Distro appears to be %s %s.\n" % (core.get_distro_data( 'display_name', '(unknown)'), core.distro_version)) log.debug("Distro = %s Distro Name = %s Display Name= %s Version = %s Supported = %s" % \ (core.distro, core.distro_name, core.distros[core.distro_name]['display_name'], \ core.distro_version, core.distro_version_supported)) distro_ok, ok = False, True if core.distro_known(): ok, distro_ok = tui.enter_yes_no( 'Is "%s %s" your correct distro/OS and version' % (core.get_distro_data('display_name', '(unknown)'), core.distro_version)) if not ok: sys.exit(0) if distro_alternate_version: core.distro_version = distro_alternate_version core.distro_changed() if not distro_ok: tui.title("DISTRO/OS SELECTION") core.distro, core.distro_version = DISTRO_UNKNOWN, DISTRO_VER_UNKNOWN log.info( log.bold( "\nChoose the name of the distro/OS that most closely matches your system:\n" )) max_name = 0 for d in core.distros_index: dd = core.distros[core.distros_index[d]] if dd['display']: max_name = max(max_name, len(dd['display_name'])) formatter = utils.TextFormatter(( { 'width': 4 }, { 'width': max_name, 'margin': 2 }, )) log.info(formatter.compose(("Num.", "Distro/OS Name"))) log.info(formatter.compose(('-' * 4, '-' * (max_name)))) d_temp = {} x = 0 for d in core.distros_index: dd = core.distros[core.distros_index[d]] if dd['display']: d_temp[x] = d log.info(formatter.compose((str(x), dd['display_name']))) x += 1 ok, y = tui.enter_range( "\nEnter number 0...%d (q=quit) ?" % (x - 1), 0, x - 1) if not ok: sys.exit(0) core.distro = d_temp[y] core.distro_name = core.distros_index[core.distro] distro_display_name = core.distros[ core.distro_name]['display_name'] log.debug("Distro = %s Distro Name = %s Display Name= %s" % (core.distro, core.distro_name, distro_display_name)) if core.distro != DISTRO_UNKNOWN: versions = core.distros[core.distro_name]['versions'].keys() versions.sort(lambda x, y: utils.compare(x, y)) log.info( log.bold( '\nChoose the version of "%s" that most closely matches your system:\n' % distro_display_name)) formatter = utils.TextFormatter(( { 'width': 4 }, { 'width': 40, 'margin': 2 }, )) log.info(formatter.compose(("Num.", "Distro/OS Version"))) log.info(formatter.compose(('-' * 4, '-' * 40))) log.info(formatter.compose(("0", "Unknown or not listed"))) x = 1 for ver in versions: ver_info = core.distros[core.distro_name]['versions'][ver] if ver_info['code_name'] and ver_info['release_date']: text = ver + ' ("' + ver_info[ 'code_name'] + '", Released ' + ver_info[ 'release_date'] + ')' elif ver_info['code_name']: text = ver + ' ("' + ver_info['code_name'] + '")' elif ver_info['release_date']: text = ver + ' (Released ' + ver_info[ 'release_date'] + ')' else: text = ver if not ver_info['supported']: text += " [Unsupported]" log.info(formatter.compose((str(x), text))) x += 1 ok, core.distro_version_int = tui.enter_range( "\nEnter number 0...%d (q=quit) ?" % (x - 1), 0, x - 1) if not ok: sys.exit(0) if core.distro_version_int == 0: core.distro_version = DISTRO_VER_UNKNOWN core.distro_version_supported = False else: core.distro_version = versions[core.distro_version_int - 1] core.distro_version_supported = core.get_ver_data( 'supported', False) log.debug("Distro = %s Distro Name = %s Display Name= %s Version = %s Supported = %s" % \ (core.distro, core.distro_name, core.distros[core.distro_name]['display_name'], \ core.distro_version, core.distro_version_supported)) core.distro_changed() log.info("\nDistro set to: %s %s" % (core.get_distro_data( 'display_name', '(unknown)'), core.distro_version)) # if core.distro == DISTRO_UNKNOWN or not core.distro_version_supported: if core.distro == DISTRO_UNKNOWN: 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." ) if num_req_missing: log.error( "The following REQUIRED dependencies are missing and need to be installed:" ) for d, desc, opt in core.missing_required_dependencies(): log.error("Missing REQUIRED dependency: %s (%s)" % (d, desc)) for d, desc, req, opt in core.missing_optional_dependencies(): if req: log.warning( "Missing OPTIONAL dependency: %s (%s) [Required for option '%s']" % (d, desc, opt)) else: log.warning( "Missing OPTIONAL dependency: %s (%s) [Optional for option '%s']" % (d, desc, opt)) sys.exit(1) # # SELECT OPTIONS TO INSTALL # if not auto: tui.title("SELECT HPLIP OPTIONS") log.info( "You can select which HPLIP options to enable. Some options require extra dependencies." ) log.info("") num_opt_missing = core.select_options(option_question_callback) else: enable_par = False core.selected_options['parallel'] = False # # COLLECT SUPERUSER PASSWORD # if not services.running_as_root(): if core.passwordObj.getAuthType() == "sudo": tui.title("ENTER USER PASSWORD") else: tui.title("ENTER ROOT/SUPERUSER PASSWORD") ok = core.check_password() if not ok: log.error( "3 incorrect attempts. (or) Insufficient permissions(i.e. try with sudo user).\nExiting." ) sys.exit(1) # INSTALLATION NOTES # if core.is_auto_installer_support(distro_alternate_version): distro_notes = core.get_distro_data('notes', '').strip() ver_notes = core.get_ver_data('notes', '', distro_alternate_version).strip() if distro_notes or ver_notes: tui.title("INSTALLATION NOTES") if distro_notes: log.info(distro_notes) if ver_notes: log.info(ver_notes) log.info("") if not tui.continue_prompt( "Please read the installation notes."): sys.exit(0) # # PRE-INSTALL COMMANDS # tui.title("RUNNING PRE-INSTALL COMMANDS") if core.run_pre_install( progress_callback, distro_alternate_version): # some cmds were run... num_req_missing = core.count_num_required_missing_dependencies() num_opt_missing = core.count_num_optional_missing_dependencies() log.info("OK") # # REQUIRED DEPENDENCIES INSTALL # package_mgr_cmd = core.get_distro_data('package_mgr_cmd') depends_to_install = [] if num_req_missing: tui.title("INSTALL MISSING REQUIRED DEPENDENCIES") log.warn("There are %d missing REQUIRED dependencies." % num_req_missing) log.notice( "Installation of dependencies requires an active internet connection." ) for depend, desc, option in core.missing_required_dependencies(): log.warning("Missing REQUIRED dependency: %s (%s)" % (depend, desc)) ok = False packages, commands = core.get_dependency_data( depend, distro_alternate_version) log.debug("Packages: %s" % ','.join(packages)) log.debug("Commands: %s" % ','.join(commands)) # if core.distro_version_supported and (packages or commands): if package_mgr_cmd and (packages or commands): if auto: answer = True else: ok, answer = tui.enter_yes_no( "\nWould you like to have this installer install the missing dependency" ) if not ok: sys.exit(0) if answer: ok = True log.debug( "Adding '%s' to list of dependencies to install." % depend) depends_to_install.append(depend) else: log.warn( "This installer cannot install '%s' for your distro/OS and/or version." % depend) if not ok: log.error( "Installation cannot continue without this dependency. Please manually install this dependency and re-run this installer." ) sys.exit(0) # # OPTIONAL dependencies # if num_opt_missing: tui.title("INSTALL MISSING OPTIONAL DEPENDENCIES") log.warn("There are %d missing OPTIONAL dependencies." % num_opt_missing) log.notice( "Installation of dependencies requires an active internet connection." ) for depend, desc, required_for_opt, opt in core.missing_optional_dependencies( ): if required_for_opt: log.warning( "Missing REQUIRED dependency for option '%s': %s (%s)" % (opt, depend, desc)) else: log.warning( "Missing OPTIONAL dependency for option '%s': %s (%s)" % (opt, depend, desc)) installed = False packages, commands = core.get_dependency_data( depend, distro_alternate_version) log.debug("Packages: %s" % ','.join(packages)) log.debug("Commands: %s" % ','.join(commands)) # if core.distro_version_supported and (packages or commands): if package_mgr_cmd and (packages or commands): if auto: answer = True else: ok, answer = tui.enter_yes_no( "\nWould you like to have this installer install the missing dependency" ) if not ok: sys.exit(0) if answer: log.debug( "Adding '%s' to list of dependencies to install." % depend) depends_to_install.append(depend) else: log.warning( "Missing dependencies may effect the proper functioning of HPLIP. Please manually install this dependency after you exit this installer." ) log.warning( "Note: Options that have REQUIRED dependencies that are missing will be turned off." ) if required_for_opt: log.warn("Option '%s' has been turned off." % opt) core.selected_options[opt] = False else: log.warn( "This installer cannot install '%s' for your distro/OS and/or version." % depend) if required_for_opt: log.warn("Option '%s' has been turned off." % opt) core.selected_options[opt] = False log.debug("Dependencies to install: %s hplip_present:%s" % (depends_to_install, core.hplip_present)) # if core.distro_version_supported and \ # (depends_to_install or core.hplip_present) and \ # core.selected_component == 'hplip': if package_mgr_cmd and \ (depends_to_install or core.hplip_present) and \ core.selected_component == 'hplip': # # CHECK FOR RUNNING PACKAGE MANAGER # User_exit, Is_pkg_mgr_running = core.close_package_managers() if User_exit: sys.exit(0) # if Is_pkg_mgr_running: # log.debug("Some Package manager are still running. ") # # CHECK FOR ACTIVE NETWORK CONNECTION # if not assume_network: tui.title("CHECKING FOR NETWORK CONNECTION") if not utils.check_network_connection(): log.error( "The network appears to be unreachable. Installation may not resolve all dependencies without access to distribution repositories." ) 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') if not ok or choice == 'n': log.info("Please connect network and try again") sys.exit(1) else: log.debug("Continuing installation without network") else: log.info("Network connection present.") # # PRE-DEPEND # tui.title("RUNNING PRE-PACKAGE COMMANDS") core.run_pre_depend(progress_callback, distro_alternate_version) log.info("OK") # # INSTALL PACKAGES AND RUN COMMANDS # tui.title("DEPENDENCY AND CONFLICT RESOLUTION") packages = [] commands_to_run = [] package_mgr_cmd = core.get_distro_data('package_mgr_cmd') # HACK! individual_pkgs = True if package_mgr_cmd.startswith('xterm'): individual_pkgs = False if package_mgr_cmd: log.debug("Preparing to install packages and run commands...") for d in depends_to_install: log.debug("*** Processing dependency: %s" % d) pkgs, commands = core.get_dependency_data( d, distro_alternate_version) if pkgs: log.debug( "Package(s) '%s' will be installed to satisfy dependency '%s'." % (','.join(pkgs), d)) packages.extend(pkgs) if commands: log.debug( "Command(s) '%s' will be run to satisfy dependency '%s'." % (','.join(commands), d)) commands_to_run.extend(commands) else: log.error("Invalid package manager") log.debug("Packages: %s" % packages) log.debug("Commands: %s" % commands_to_run) log.debug("Install individual packages: %s" % individual_pkgs) if package_mgr_cmd and packages: if individual_pkgs: for packages_to_install in packages: retries = 0 while True: cmd = utils.cat(package_mgr_cmd) log.debug("Package manager command: %s" % cmd) log.info( "Running '%s'\nPlease wait, this may take several minutes..." % cmd) status, output = utils.run(cmd, core.passwordObj) if status != 0: retries += 1 if retries < (max_retries + 1): log.error("Command failed. Re-try #%d..." % retries) continue log.error( "Package install command failed with error code %d" % status) ok, ans = tui.enter_yes_no( "Would you like to retry installing the missing package(s)" ) if not ok: sys.exit(0) if ans: continue else: log.warn( "Some HPLIP functionality might not function due to missing package(s)." ) break else: break else: packages_to_install = ' '.join(packages) while True: cmd = utils.cat(package_mgr_cmd) log.debug("Package manager command: %s" % cmd) log.info( "Running '%s'\nPlease wait, this may take several minutes..." % cmd) status, output = utils.run(cmd, core.passwordObj) if status != 0: log.error( "Package install command failed with error code %d" % status) ok, ans = tui.enter_yes_no( "Would you like to retry installing the missing package(s)" ) if not ok: sys.exit(0) if ans: continue else: log.warn( "Some HPLIP functionality might not function due to missing package(s)." ) break else: break if commands_to_run: for cmd in commands_to_run: log.debug(cmd) log.info( "Running '%s'\nPlease wait, this may take several minutes..." % cmd) status, output = utils.run(cmd, core.passwordObj) if status != 0: log.error("Install command failed with error code %d" % status) sys.exit(1) # # HPLIP REMOVE # num_req_missing = 0 core.check_dependencies() for depend, desc, opt in core.missing_required_dependencies(): log.error("A required dependency '%s (%s)' is still missing." % (depend, desc)) num_req_missing += 1 if num_req_missing == 0 and core.hplip_present and core.selected_component == 'hplip' and core.distro_version_supported: path = utils.which('hp-uninstall') 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'], 'i') if not ok or choice == 'q': log.error("User Exit") sys.exit(0) elif choice == 'i': # log.info("Uninstalling existing HPLIP-%s"%prev_hplip_version) sts = core.uninstall(NON_INTERACTIVE_MODE) if sts is False: log.warn( "Failed to uninstall existing HPLIP-%s. This installation will overwrite on existing HPLIP" % prev_hplip_version) else: log.debug("HPLIP-%s is uninstalled successfully." % prev_hplip_version) # # POST-DEPEND # tui.title("RUNNING POST-PACKAGE COMMANDS") core.run_post_depend(progress_callback) log.info("OK") # # DEPENDENCIES RE-CHECK # tui.title("RE-CHECKING DEPENDENCIES") core.check_dependencies() num_req_missing = 0 for depend, desc, opt in core.missing_required_dependencies(): num_req_missing += 1 log.error("A required dependency '%s (%s)' is still missing." % (depend, desc)) if num_req_missing: if num_req_missing > 1: log.error( "Installation cannot continue without these dependencies." ) else: log.error( "Installation cannot continue without this dependency." ) log.error( "Please manually install this dependency and re-run this installer." ) sys.exit(1) for depend, desc, required_for_opt, opt in core.missing_optional_dependencies( ): if required_for_opt: log.warn( "An optional dependency '%s (%s)' is still missing." % (depend, desc)) log.warn("Option '%s' has been turned off." % opt) core.selected_options[opt] = False else: log.warn( "An optional dependency '%s (%s)' is still missing." % (depend, desc)) log.warn("Some features may not function as expected.") if not num_opt_missing and not num_req_missing: log.info("OK") # # INSTALL LOCATION # log.debug("Install location = %s" % core.install_location) # # BUILD AND INSTALL # if not auto: tui.title("READY TO BUILD AND INSTALL") if not tui.continue_prompt("Ready to perform build and install."): sys.exit(0) tui.title("PRE-BUILD COMMANDS") core.run_pre_build(progress_callback, distro_alternate_version) log.info("OK") tui.title("BUILD AND INSTALL") os.umask(0022) for cmd in core.build_cmds(): log.info( "Running '%s'\nPlease wait, this may take several minutes..." % cmd) status, output = utils.run(cmd, core.passwordObj) if status != 0: if 'configure' in cmd: log.error( "Configure failed with error: %s" % (CONFIGURE_ERRORS.get(status, CONFIGURE_ERRORS[1]))) else: log.error("'%s' command failed with status code %d" % (cmd, status)) sys.exit(0) else: log.info("Command completed successfully.") log.info("") log.info("\nBuild complete.") # # POST BUILD # tui.title("POST-BUILD COMMANDS") core.run_post_build(progress_callback, distro_alternate_version) try: from prnt import cups #This call is just to update the cups PPD cache file@ /var/cache/cups/ppds.dat. If this is not called, hp-setup picks incorrect ppd 1st time for some printers. cups.getSystemPPDs() except ImportError: log.error("Failed to Import Cups") # # OPEN MDNS MULTICAST PORT # user_conf = UserConfig() if core.selected_options['network']: open_mdns_port = core.get_distro_ver_data( 'open_mdns_port', None, distro_alternate_version) if open_mdns_port: tui.title( "OPEN MDNS/BONJOUR FIREWALL PORT (MULTICAST PORT 5353)") 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." for p in tui.format_paragraph(paragraph): log.info(p) log.info("") ok, ans = tui.enter_yes_no( "Do you wish to open this port on your internet firewall") if not ok: sys.exit(0) if ans: services.run_open_mdns_port(core, core.passwordObj) else: 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'." ) # # Try to close running hp-systray (3.9.2 or later) # if current_version >= 0x030902: # 3.9.2 try: from dbus import SessionBus, lowlevel except ImportError: pass else: try: args = [ '', '', EVENT_SYSTEMTRAY_EXIT, prop.username, 0, '', '' ] msg = lowlevel.SignalMessage('/', 'com.hplip.StatusService', 'Event') msg.append(signature='ssisiss', *args) tui.title("CLOSE HP_SYSTRAY") log.info( "Sending close message to hp-systray (if it is currently running)..." ) SessionBus().send_message(msg) time.sleep(0.5) except: pass tui.title("HPLIP UPDATE NOTIFICATION") ok, choice = tui.enter_choice( "Do you want to check for HPLIP updates?. (y=yes*, n=no) : ", ['y', 'n'], 'y') if not ok or choice != 'y': user_conf.set('upgrade', 'notify_upgrade', 'false') else: user_conf.set('upgrade', 'notify_upgrade', 'true') user_conf.set('upgrade', 'last_upgraded_time', str(int(time.time()))) user_conf.set('upgrade', 'pending_upgrade_time', '0') if prev_hplip_plugin_status != pluginhandler.PLUGIN_NOT_INSTALLED: tui.title("HPLIP PLUGIN UPDATE NOTIFICATION") ok, choice = tui.enter_choice( "HPLIP Plug-in's needs to be installed/updated. Do you want to update plug-in's?. (y=yes*, n=no) : ", ['y', 'n'], 'y') if ok and choice == 'y': ok, choice = tui.enter_choice( "Do you want to install plug-in's in GUI mode?. (u=GUI mode*, i=Interactive mode) : ", ['u', 'i'], 'u') if ok and choice == 'u': if not services.run_hp_tools_with_auth( 'hp-plugin', core.passwordObj): log.error( "hp-plugin command failed. Please run hp-plugin manually." ) elif ok and choice == 'i': plugin_cmd = core.passwordObj.getAuthCmd( ) % 'hp-plugin -i' log.info("Running '%s' command...." % plugin_cmd) if os_utils.execute(plugin_cmd) != 0: log.error( "hp-plugin command failed. Please run hp-plugin manually." ) else: log.info( log.bold( "Please install hp plugin's manually, otherwise some functionality may break" )) else: log.info( log.bold( "Please install hp plugin's manually, otherwise some functionality may break" )) if core.selected_component == 'hplip': tui.title("RESTART OR RE-PLUG IS REQUIRED") cmd = "hp-setup" 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 for p in tui.format_paragraph(paragraph): log.info(p) log.info("") ok, choice = tui.enter_choice( "Restart or re-plug in your printer (r=restart, p=re-plug in*, i=ignore/continue, q=quit) : ", ['r', 'p', 'i'], 'p') if not ok: tui.title("RE-STARTING HP_SYSTRAY") services.run_systray() sys.exit(0) if choice == 'r': log.note("") log.note( "IMPORTANT! Make sure to save all work in all open applications before restarting!" ) ok, ans = tui.enter_yes_no(log.bold("Restart now"), 'n') if not ok: tui.title("RE-STARTING HP_SYSTRAY") services.run_systray() sys.exit(0) if ans: ok = services.restart(core.passwordObj) if not ok: log.error( "Restart failed. Please restart using the system menu." ) tui.title("RE-STARTING HP_SYSTRAY") services.run_systray() sys.exit(0) elif choice == 'p': # 'p' if not tui.continue_prompt( "Please unplug and re-plugin your printer now. "): tui.title("RE-STARTING HP_SYSTRAY") services.run_systray() sys.exit(0) # # SETUP PRINTER # if core.selected_component == 'hplip': tui.title("PRINTER SETUP") if auto: install_printer = True else: ok, install_printer = tui.enter_yes_no( "Would you like to setup a printer now") if not ok: tui.title("RE-STARTING HP_SYSTRAY") services.run_systray() sys.exit(0) if install_printer: log.info( "Please make sure your printer is connected and powered on at this time." ) ok, choice = tui.enter_choice( "Do you want to setup printer in GUI mode? (u=GUI mode*, i=Interactive mode) : ", ['u', 'i'], 'u') if ok and choice == 'u': if not services.run_hp_tools_with_auth( 'hp-setup', core.passwordObj): log.error( "hp-setup failed. Please run hp-setup manually.") elif ok and choice == 'i': setup_cmd = core.passwordObj.getAuthCmd() % 'hp-setup -i' log.info("Running '%s' command...." % setup_cmd) if os_utils.execute(setup_cmd) != 0: log.error( "hp-setup failed. Please run hp-setup manually.") tui.title("RE-STARTING HP_SYSTRAY") services.run_systray() except KeyboardInterrupt: log.info("") log.error("Aborted.") sys.exit(0)
def __init__(self, user=False): self.bus = SessionBus() if user else SystemBus() systemd = self.bus.get_object(SYSTEMD_BUSNAME, SYSTEMD_PATH) self.manager = Interface(systemd, dbus_interface=SYSTEMD_MANAGER_INTERFACE)
def start(language, auto=True, test_depends=False, test_unknown=False, assume_network=False, max_retries=3, enable=None, disable=None): try: core = CoreInstall(MODE_INSTALLER, INTERACTIVE_MODE) current_version = prop.installed_version_int log.debug("Currently installed version: 0x%06x" % current_version) core.enable = enable core.disable = disable if core.running_as_root(): log.error( "You are running the installer as root. It is highly recommended that you run the installer as" ) log.error( "a regular (non-root) user. Do you still wish to continue?") ok, ans = tui.enter_yes_no(log.bold("Continue with installation"), 'n') if not ans or not ok: sys.exit(1) if auto: log.note( "Running in automatic mode. The most common options will be selected." ) log.info("") log.note( "Defaults for each question are maked with a '*'. Press <enter> to accept the default." ) if not auto: tui.title("INSTALLATION MODE") log.info( "Automatic mode will install the full HPLIP solution with the most common options." ) log.info( "Custom mode allows you to choose installation options to fit specific requirements." ) #if os.getenv('DISPLAY') and utils.find_browser() is not None: if 0: ok, choice = tui.enter_choice( "\nPlease choose the installation mode (a=automatic*, c=custom, w=web installer, q=quit) : ", ['a', 'c', 'w'], 'a') else: ok, choice = tui.enter_choice( "\nPlease choose the installation mode (a=automatic*, c=custom, q=quit) : ", ['a', 'c'], 'a') if not ok: sys.exit(0) if choice == 'a': auto = True elif choice == 'w': import web_install log.debug("Starting web browser installer...") web_install.start(language) return log.info("\nInitializing. Please wait...") core.init() if test_unknown: core.distro_name = 'unknown' core.distro = 0 core.distro_version = 0 # # HPLIP vs. HPIJS INSTALLATION # #if not auto: #tui.title("INSTALL TYPE") #log.info("For most users, it is recommended to install HPLIP with full support (scanning, faxing, toolbox, etc).") #log.info("For servers or minimal installations, you can also install print support only (HPIJS only).") #ok, choice = tui.enter_choice("\nInstall full hplip support (recommended) or print-only support (f=full hplip support*, p=printing only support, q=quit) ?", #['f', 'p'], 'f') #if not ok: sys.exit(0) #if choice == 'p': #core.selected_component = 'hpijs' #log.debug(core.selected_component) core.selected_component = 'hplip' # # INTRODUCTION # tui.title("INTRODUCTION") if core.selected_component == 'hplip': log.info( "This installer will install HPLIP version %s on your computer." % core.version_public) #core.hpijs_build = False #else: #log.info("This installer will install HPIJS version %s on your computer." % core.version_public) #core.hpijs_build = True log.info( "Please close any running package management systems now (YaST, Adept, Synaptic, Up2date, etc)." ) ## # ## # RELEASE NOTES ## # ## ## if not auto: ## if os.getenv('DISPLAY'): ## tui.title("VIEW RELEASE NOTES") ## log.info("Release notes from this version are available as a web (HTML) document.") ## log.info("The release notes file will be shown in a separate web browser window.") ## ## ok, ans = tui.enter_yes_no("\nWould you like to view the release notes for this version of HPLIP", 'n') ## ## if ok and ans: ## log.info("Displaying release notes in a browser window...") ## core.show_release_notes_in_browser() ## ## if not ok: ## sys.exit(0) # For testing, mark all dependencies missing if test_depends: for d in core.have_dependencies: core.have_dependencies[d] = False num_req_missing = core.count_num_required_missing_dependencies() num_opt_missing = core.count_num_optional_missing_dependencies() # # CONFIRM AND SELECT DISTRO NAME AND VERSION # tui.title("DISTRO/OS CONFIRMATION") if core.distro_known(): log.info("Distro appears to be %s %s.\n" % (core.get_distro_data( 'display_name', '(unknown)'), core.distro_version)) log.debug("Distro = %s Distro Name = %s Display Name= %s Version = %s Supported = %s" % \ (core.distro, core.distro_name, core.distros[core.distro_name]['display_name'], \ core.distro_version, core.distro_version_supported)) distro_ok, ok = False, True if core.distro_known(): ok, distro_ok = tui.enter_yes_no( 'Is "%s %s" your correct distro/OS and version' % (core.get_distro_data('display_name', '(unknown)'), core.distro_version)) if not ok: sys.exit(0) core.distro_changed() if not distro_ok: tui.title("DISTRO/OS SELECTION") core.distro, core.distro_version = DISTRO_UNKNOWN, DISTRO_VER_UNKNOWN log.info( log.bold( "\nChoose the name of the distro/OS that most closely matches your system:\n" )) max_name = 0 for d in core.distros_index: dd = core.distros[core.distros_index[d]] if dd['display']: max_name = max(max_name, len(dd['display_name'])) formatter = utils.TextFormatter(( { 'width': 4 }, { 'width': max_name, 'margin': 2 }, )) log.info(formatter.compose(("Num.", "Distro/OS Name"))) log.info(formatter.compose(('-' * 4, '-' * (max_name)))) d_temp = {} x = 0 for d in core.distros_index: dd = core.distros[core.distros_index[d]] if dd['display']: d_temp[x] = d log.info(formatter.compose((str(x), dd['display_name']))) x += 1 ok, y = tui.enter_range( "\nEnter number 0...%d (q=quit) ?" % (x - 1), 0, x - 1) if not ok: sys.exit(0) core.distro = d_temp[y] core.distro_name = core.distros_index[core.distro] distro_display_name = core.distros[ core.distro_name]['display_name'] log.debug("Distro = %s Distro Name = %s Display Name= %s" % (core.distro, core.distro_name, distro_display_name)) if core.distro != DISTRO_UNKNOWN: versions = core.distros[core.distro_name]['versions'].keys() versions.sort(lambda x, y: core.sort_vers(x, y)) log.info( log.bold( '\nChoose the version of "%s" that most closely matches your system:\n' % distro_display_name)) formatter = utils.TextFormatter(( { 'width': 4 }, { 'width': 40, 'margin': 2 }, )) log.info(formatter.compose(("Num.", "Distro/OS Version"))) log.info(formatter.compose(('-' * 4, '-' * 40))) log.info(formatter.compose(("0", "Unknown or not listed"))) x = 1 for ver in versions: ver_info = core.distros[core.distro_name]['versions'][ver] if ver_info['code_name'] and ver_info['release_date']: text = ver + ' ("' + ver_info[ 'code_name'] + '", Released ' + ver_info[ 'release_date'] + ')' elif ver_info['code_name']: text = ver + ' ("' + ver_info['code_name'] + '")' elif ver_info['release_date']: text = ver + ' (Released ' + ver_info[ 'release_date'] + ')' else: text = ver if not ver_info['supported']: text += " [Unsupported]" log.info(formatter.compose((str(x), text))) x += 1 ok, core.distro_version_int = tui.enter_range( "\nEnter number 0...%d (q=quit) ?" % (x - 1), 0, x - 1) if not ok: sys.exit(0) if core.distro_version_int == 0: core.distro_version = DISTRO_VER_UNKNOWN core.distro_version_supported = False else: core.distro_version = versions[core.distro_version_int - 1] core.distro_version_supported = core.get_ver_data( 'supported', False) log.debug("Distro = %s Distro Name = %s Display Name= %s Version = %s Supported = %s" % \ (core.distro, core.distro_name, core.distros[core.distro_name]['display_name'], \ core.distro_version, core.distro_version_supported)) core.distro_changed() log.info("\nDistro set to: %s %s" % (core.get_distro_data( 'display_name', '(unknown)'), core.distro_version)) if core.distro == DISTRO_UNKNOWN or not core.distro_version_supported: 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." ) if num_req_missing: log.error( "The following REQUIRED dependencies are missing and need to be installed:" ) for d, desc, opt in core.missing_required_dependencies(): log.error("Missing REQUIRED dependency: %s (%s)" % (d, desc)) for d, desc, req, opt in core.missing_optional_dependencies(): if req: log.warning( "Missing OPTIONAL dependency: %s (%s) [Required for option '%s']" % (d, desc, opt)) else: log.warning( "Missing OPTIONAL dependency: %s (%s) [Optional for option '%s']" % (d, desc, opt)) sys.exit(1) # # SELECT OPTIONS TO INSTALL # if not auto: tui.title("SELECT HPLIP OPTIONS") log.info( "You can select which HPLIP options to enable. Some options require extra dependencies." ) log.info("") num_opt_missing = core.select_options(option_question_callback) #else: # auto #ok, enable_par = tui.enter_yes_no("Would you like to enable support for parallel (LPT:) connected printers?", 'n') #if not ok: sys.exit(0) #core.selected_options['parallel'] = enable_par #if enable_par: #log.info("Parallel support enabled.") else: enable_par = False core.selected_options['parallel'] = False log.debug("Req missing=%d Opt missing=%d HPLIP=%s Component=%s" % \ (num_req_missing, num_opt_missing, core.hplip_present, core.selected_component)) # # COLLECT SUPERUSER PASSWORD # if not core.running_as_root(): su_sudo = core.get_distro_data('su_sudo') if su_sudo == "sudo": tui.title("ENTER USER PASSWORD") ok = core.check_password(password_user_entry, progress_callback) else: tui.title("ENTER ROOT/SUPERUSER PASSWORD") ok = core.check_password(password_entry, progress_callback) if not ok: log.error("3 incorrect attempts. Exiting.") sys.exit(1) # # INSTALLATION NOTES # if core.distro_supported(): distro_notes = core.get_distro_data('notes', '').strip() ver_notes = core.get_ver_data('notes', '').strip() if distro_notes or ver_notes: tui.title("INSTALLATION NOTES") if distro_notes: log.info(distro_notes) if ver_notes: log.info(ver_notes) log.info("") if not tui.continue_prompt( "Please read the installation notes."): sys.exit(0) # # PRE-INSTALL COMMANDS # tui.title("RUNNING PRE-INSTALL COMMANDS") if core.run_pre_install(progress_callback): # some cmds were run... num_req_missing = core.count_num_required_missing_dependencies() num_opt_missing = core.count_num_optional_missing_dependencies() log.info("OK") # # REQUIRED DEPENDENCIES INSTALL # depends_to_install = [] if num_req_missing: tui.title("INSTALL MISSING REQUIRED DEPENDENCIES") log.warn("There are %d missing REQUIRED dependencies." % num_req_missing) log.notice( "Installation of dependencies requires an active internet connection." ) for depend, desc, option in core.missing_required_dependencies(): log.warning("Missing REQUIRED dependency: %s (%s)" % (depend, desc)) ok = False packages, commands = core.get_dependency_data(depend) log.debug("Packages: %s" % ','.join(packages)) log.debug("Commands: %s" % ','.join(commands)) if core.distro_version_supported and (packages or commands): if auto: answer = True else: ok, answer = tui.enter_yes_no( "\nWould you like to have this installer install the missing dependency" ) if not ok: sys.exit(0) if answer: ok = True log.debug( "Adding '%s' to list of dependencies to install." % depend) depends_to_install.append(depend) else: log.warn( "This installer cannot install '%s' for your distro/OS and/or version." % depend) if not ok: log.error( "Installation cannot continue without this dependency. Please manually install this dependency and re-run this installer." ) sys.exit(0) #log.info("-"*10) #log.info("") # # OPTIONAL dependencies # if num_opt_missing: tui.title("INSTALL MISSING OPTIONAL DEPENDENCIES") log.warn("There are %d missing OPTIONAL dependencies." % num_opt_missing) log.notice( "Installation of dependencies requires an active internet connection." ) for depend, desc, required_for_opt, opt in core.missing_optional_dependencies( ): if required_for_opt: log.warning( "Missing REQUIRED dependency for option '%s': %s (%s)" % (opt, depend, desc)) else: log.warning( "Missing OPTIONAL dependency for option '%s': %s (%s)" % (opt, depend, desc)) installed = False packages, commands = core.get_dependency_data(depend) log.debug("Packages: %s" % ','.join(packages)) log.debug("Commands: %s" % ','.join(commands)) if core.distro_version_supported and (packages or commands): if auto: answer = True else: ok, answer = tui.enter_yes_no( "\nWould you like to have this installer install the missing dependency" ) if not ok: sys.exit(0) if answer: log.debug( "Adding '%s' to list of dependencies to install." % depend) depends_to_install.append(depend) else: log.warning( "Missing dependencies may effect the proper functioning of HPLIP. Please manually install this dependency after you exit this installer." ) log.warning( "Note: Options that have REQUIRED dependencies that are missing will be turned off." ) if required_for_opt: log.warn("Option '%s' has been turned off." % opt) core.selected_options[opt] = False else: log.warn( "This installer cannot install '%s' for your distro/OS and/or version." % depend) if required_for_opt: log.warn("Option '%s' has been turned off." % opt) core.selected_options[opt] = False #log.info("-"*10) #log.info("") log.debug("Dependencies to install: %s" % depends_to_install) if core.distro_version_supported and \ (depends_to_install or core.hplip_present) and \ core.selected_component == 'hplip': # # CHECK FOR RUNNING PACKAGE MANAGER # pid, cmdline = core.check_pkg_mgr() while pid: 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) :" % cmdline, ['i', 'r', 'q', 'f'], 'r') if not ok: sys.exit(0) if user_input == 'i': log.warn( "Ignoring running package manager. Some package operations may fail." ) break if user_input == 'f': ok, ans = tui.enter_yes_no( "\nForce quit of package manager '%s'" % cmdline, 'y') if not ok: sys.exit(0) if ans: cmd = core.su_sudo() % ("kill %d" % pid) status, output = core.run(cmd) if status != 0: log.error( "Failed to kill process. You may need to manually quit the program." ) pid, cmdline = core.check_pkg_mgr() # # CHECK FOR ACTIVE NETWORK CONNECTION # if not assume_network: tui.title("CHECKING FOR NETWORK CONNECTION") if not core.check_network_connection(): log.error( "\nThe network appears to be unreachable. Installation cannot complete without access to" ) log.error( "distribution repositories. Please check the network and try again." ) sys.exit(1) else: log.info("Network connection present.") # # PRE-DEPEND # tui.title("RUNNING PRE-PACKAGE COMMANDS") core.run_pre_depend(progress_callback) log.info("OK") # # INSTALL PACKAGES AND RUN COMMANDS # tui.title("DEPENDENCY AND CONFLICT RESOLUTION") packages = [] commands_to_run = [] package_mgr_cmd = core.get_distro_data('package_mgr_cmd') # HACK! individual_pkgs = True if package_mgr_cmd.startswith('xterm'): individual_pkgs = False if package_mgr_cmd: log.debug("Preparing to install packages and run commands...") for d in depends_to_install: log.debug("*** Processing dependency: %s" % d) pkgs, commands = core.get_dependency_data(d) if pkgs: log.debug( "Package(s) '%s' will be installed to satisfy dependency '%s'." % (','.join(pkgs), d)) packages.extend(pkgs) if commands: log.debug( "Command(s) '%s' will be run to satisfy dependency '%s'." % (','.join(commands), d)) commands_to_run.extend(commands) else: log.error("Invalid package manager") log.debug("Packages: %s" % packages) log.debug("Commands: %s" % commands_to_run) log.debug("Install individual packages: %s" % individual_pkgs) if package_mgr_cmd and packages: if individual_pkgs: for packages_to_install in packages: retries = 0 while True: cmd = utils.cat(package_mgr_cmd) log.debug("Package manager command: %s" % cmd) log.info( "Running '%s'\nPlease wait, this may take several minutes..." % cmd) status, output = core.run(cmd) if status != 0: retries += 1 if retries < (max_retries + 1): log.error("Command failed. Re-try #%d..." % retries) continue log.error( "Package install command failed with error code %d" % status) ok, ans = tui.enter_yes_no( "Would you like to retry installing the missing package(s)" ) if not ok: sys.exit(0) if ans: continue else: log.warn( "Some HPLIP functionality might not function due to missing package(s)." ) break else: break else: packages_to_install = ' '.join(packages) while True: cmd = utils.cat(package_mgr_cmd) log.debug("Package manager command: %s" % cmd) log.info( "Running '%s'\nPlease wait, this may take several minutes..." % cmd) status, output = core.run(cmd) if status != 0: log.error( "Package install command failed with error code %d" % status) ok, ans = tui.enter_yes_no( "Would you like to retry installing the missing package(s)" ) if not ok: sys.exit(0) if ans: continue else: log.warn( "Some HPLIP functionality might not function due to missing package(s)." ) break else: break if commands_to_run: for cmd in commands_to_run: log.debug(cmd) log.info( "Running '%s'\nPlease wait, this may take several minutes..." % cmd) status, output = core.run(cmd) if status != 0: log.error("Install command failed with error code %d" % status) sys.exit(1) ## ## HPOJ REMOVAL ## #if core.hpoj_present and core.selected_component == 'hplip' and core.distro_version_supported: #log.error("HPOJ is installed and/or running. HPLIP is not compatible with HPOJ.") #failed = True #hpoj_remove_cmd = core.get_distro_data('hpoj_remove_cmd') #if hpoj_remove_cmd: #if auto: #answer = True #else: #ok, answer = tui.enter_yes_no("\nWould you like to have this installer attempt to uninstall HPOJ") #if not ok: sys.exit(0) #if answer: #failed = core.remove_hpoj(progress_callback) #if failed: #log.error("HPOJ removal failed. Please manually stop/remove/uninstall HPOJ and then re-run this installer.") #sys.exit(1) #else: #log.error("Please stop/remove/uninstall HPOJ and then re-run this installer.") #sys.exit(1) #else: #log.error("Please stop/remove/uninstall HPOJ and then re-run this installer.") #sys.exit(1) # # HPLIP REMOVE # if core.hplip_present and core.selected_component == 'hplip' and core.distro_version_supported: failed = True log.warn( "A previous install of HPLIP is installed and/or running.") hplip_remove_cmd = core.get_distro_data('hplip_remove_cmd') if hplip_remove_cmd: if auto: answer = True else: ok, answer = tui.enter_yes_no( "\nWould you like to have this installer attempt to uninstall the previously installed HPLIP" ) if not ok: sys.exit(0) if answer: failed = core.remove_hplip(progress_callback) else: log.error( "The previously installed version of HPLIP may conflict with the new one being installed." ) log.error( "It is recommended that you quit this installer, and manually remove HPLIP before continuing." ) sys.exit(0) if failed: log.warn( "HPLIP removal failed. The previous install may have been installed using a tarball or this installer." ) log.warn( "Continuing to run installer - this installation should overwrite the previous one." ) # # POST-DEPEND # tui.title("RUNNING POST-PACKAGE COMMANDS") core.run_post_depend(progress_callback) log.info("OK") # # DEPENDENCIES RE-CHECK # tui.title("RE-CHECKING DEPENDENCIES") core.check_dependencies() num_req_missing = 0 for depend, desc, opt in core.missing_required_dependencies(): num_req_missing += 1 log.error("A required dependency '%s (%s)' is still missing." % (depend, desc)) if num_req_missing: if num_req_missing > 1: log.error( "Installation cannot continue without these dependencies." ) else: log.error( "Installation cannot continue without this dependency." ) log.error( "Please manually install this dependency and re-run this installer." ) sys.exit(1) for depend, desc, required_for_opt, opt in core.missing_optional_dependencies( ): if required_for_opt: log.warn( "An optional dependency '%s (%s)' is still missing." % (depend, desc)) log.warn("Option '%s' has been turned off." % opt) core.selected_options[opt] = False else: log.warn( "An optional dependency '%s (%s)' is still missing." % (depend, desc)) log.warn("Some features may not function as expected.") if not num_opt_missing and not num_req_missing: log.info("OK") # # INSTALL LOCATION # log.debug("Install location = %s" % core.install_location) # # BUILD AND INSTALL # if not auto: tui.title("READY TO BUILD AND INSTALL") if not tui.continue_prompt("Ready to perform build and install."): sys.exit(0) tui.title("PRE-BUILD COMMANDS") core.run_pre_build(progress_callback) log.info("OK") tui.title("BUILD AND INSTALL") os.umask(0022) for cmd in core.build_cmds(): log.info( "Running '%s'\nPlease wait, this may take several minutes..." % cmd) status, output = core.run(cmd) if status != 0: if 'configure' in cmd: log.error( "Configure failed with error: %s" % CONFIGURE_ERRORS.get(status, CONFIGURE_ERRORS[1])) else: log.error("'%s' command failed with status code %d" % (cmd, status)) sys.exit(0) else: log.info("Command completed successfully.") log.info("") log.info("\nBuild complete.") # # POST BUILD # tui.title("POST-BUILD COMMANDS") core.run_post_build(progress_callback) # # OPEN MDNS MULTICAST PORT # if core.selected_options['network']: open_mdns_port = core.get_distro_ver_data('open_mdns_port') if open_mdns_port: tui.title( "OPEN MDNS/BONJOUR FIREWALL PORT (MULTICAST PORT 5353)") 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." for p in tui.format_paragraph(paragraph): log.info(p) log.info("") ok, ans = tui.enter_yes_no( "Do you wish to open this port on your internet firewall") if not ok: sys.exit(0) if ans: core.run_open_mdns_port() else: 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'." ) # # Try to close running hp-systray (3.9.2 or later) # if current_version >= 0x030902: # 3.9.2 try: # dBus #import dbus from dbus import SessionBus, lowlevel except ImportError: #log.error("Unable to load DBus") pass else: try: args = [ '', '', EVENT_SYSTEMTRAY_EXIT, prop.username, 0, '', '' ] msg = lowlevel.SignalMessage('/', 'com.hplip.StatusService', 'Event') msg.append(signature='ssisiss', *args) tui.title("CLOSE HP_SYSTRAY") log.info( "Sending close message to hp-systray (if it is currently running)..." ) SessionBus().send_message(msg) except: pass # Restart or re-plugin if necessary (always True in 2.7.9+) if core.selected_component == 'hplip': tui.title("RESTART OR RE-PLUG IS REQUIRED") cmd = "hp-setup" 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 for p in tui.format_paragraph(paragraph): log.info(p) log.info("") ok, choice = tui.enter_choice( "Restart or re-plug in your printer (r=restart, p=re-plug in*, i=ignore/continue, q=quit) : ", ['r', 'p', 'i'], 'p') if not ok: sys.exit(0) if choice == 'r': log.note("") log.note( "IMPORTANT! Make sure to save all work in all open applications before restarting!" ) ok, ans = tui.enter_yes_no(log.bold("Restart now"), 'n') if not ok: sys.exit(0) if ans: ok = core.restart() if not ok: log.error( "Restart failed. Please restart using the system menu." ) sys.exit(0) elif choice == 'p': # 'p' if not tui.continue_prompt( "Please unplug and re-plugin your printer now. "): sys.exit(0) # # SETUP PRINTER # if core.selected_component == 'hplip': tui.title("PRINTER SETUP") if auto: install_printer = True else: ok, install_printer = tui.enter_yes_no( "Would you like to setup a printer now") if not ok: sys.exit(0) if install_printer: log.info( "Please make sure your printer is connected and powered on at this time." ) if not core.run_hp_setup(): log.error("hp-setup failed. Please run hp-setup manually.") except KeyboardInterrupt: log.info("") log.error("Aborted.") sys.exit(0)
def __new__(cls, name, bus=None, allow_replacement=False, replace_existing=False, do_not_queue=False): """Constructor, which may either return an existing cached object or a new object. :Parameters: `name` : str The well-known name to be advertised `bus` : dbus.Bus A Bus on which this service will be advertised. Omitting this parameter or setting it to None has been deprecated since version 0.82.1. For backwards compatibility, if this is done, the global shared connection to the session bus will be used. `allow_replacement` : bool If True, other processes trying to claim the same well-known name will take precedence over this one. `replace_existing` : bool If True, this process can take over the well-known name from other processes already holding it. `do_not_queue` : bool If True, this service will not be placed in the queue of services waiting for the requested name if another service already holds it. """ validate_bus_name(name, allow_well_known=True, allow_unique=False) # if necessary, get default bus (deprecated) if bus is None: import warnings warnings.warn( 'Omitting the "bus" parameter to ' 'dbus.service.BusName.__init__ is deprecated', DeprecationWarning, stacklevel=2) bus = SessionBus() # see if this name is already defined, return it if so # FIXME: accessing internals of Bus if name in bus._bus_names: return bus._bus_names[name] # otherwise register the name name_flags = \ (allow_replacement and _dbus_bindings. NAME_FLAG_ALLOW_REPLACEMENT or 0) | \ (replace_existing and _dbus_bindings. NAME_FLAG_REPLACE_EXISTING or 0) | \ (do_not_queue and _dbus_bindings. NAME_FLAG_DO_NOT_QUEUE or 0) retval = bus.request_name(name, name_flags) # TODO: more intelligent tracking of bus name states? if retval == _dbus_bindings.REQUEST_NAME_REPLY_PRIMARY_OWNER: pass elif retval == _dbus_bindings.REQUEST_NAME_REPLY_IN_QUEUE: # queueing can happen by default, maybe we should # track this better or let the user know if they're # queued or not? pass elif retval == _dbus_bindings.REQUEST_NAME_REPLY_EXISTS: raise NameExistsException(name) elif retval == _dbus_bindings.REQUEST_NAME_REPLY_ALREADY_OWNER: # if this is a shared bus which is being used by someone # else in this process, this can happen legitimately pass else: raise RuntimeError( 'requesting bus name %s returned unexpected value %s' % (name, retval)) # and create the object bus_name = object.__new__(cls) bus_name._bus = bus bus_name._name = name # cache instance (weak ref only) # FIXME: accessing Bus internals again bus._bus_names[name] = bus_name return bus_name
def notify(self, title, body, notify_type, **kwargs): """ Perform DBus Notification """ if not self._enabled or MAINLOOP_MAP[self.schema] is None: self.logger.warning( "{} notifications could not be loaded.".format(self.schema)) return False # Acquire our session session = SessionBus(mainloop=MAINLOOP_MAP[self.schema]) # acquire our dbus object dbus_obj = session.get_object( NOTIFY_DBUS_INTERFACE, NOTIFY_DBUS_SETTING_LOCATION, ) # Acquire our dbus interface dbus_iface = Interface( dbus_obj, dbus_interface=NOTIFY_DBUS_INTERFACE, ) # image path icon_path = self.image_path(notify_type, extension='.ico') # Our meta payload meta_payload = { "urgency": Byte(self.urgency) } if not (self.x_axis is None and self.y_axis is None): # Set x/y access if these were set meta_payload['x'] = self.x_axis meta_payload['y'] = self.y_axis if NOTIFY_DBUS_IMAGE_SUPPORT is True: try: # Use Pixbuf to create the proper image type image = GdkPixbuf.Pixbuf.new_from_file(icon_path) # Associate our image to our notification meta_payload['icon_data'] = ( image.get_width(), image.get_height(), image.get_rowstride(), image.get_has_alpha(), image.get_bits_per_sample(), image.get_n_channels(), ByteArray(image.get_pixels()) ) except Exception as e: self.logger.warning( "Could not load Gnome notification icon ({}): {}" .format(icon_path, e)) # Limit results to just the first 10 line otherwise # there is just to much content to display body = re.split('[\r\n]+', body) if title: # Place title on first line if it exists body.insert(0, title) body = '\r\n'.join(body[0:10]) try: dbus_iface.Notify( # Application Identifier self.app_id, # Message ID (0 = New Message) 0, # Icon (str) - not used '', # Title str(title), # Body str(body), # Actions list(), # Meta meta_payload, # Message Timeout self.message_timeout_ms, ) self.logger.info('Sent DBus notification.') except Exception as e: self.logger.warning('Failed to send DBus notification.') self.logger.exception('DBus Exception') return False return True
def get_dbus_proxy_object(): return SessionBus().get_object(UNITY_BUS_NAME, DEBUG_PATH)
class Server(SingleTestsImpl, TestsImpl, SignalTestsImpl): def triggered_by_client(self, parameter1, parameter2, sender, sender_path): # Called when the client emits TestSignals.Trigger from any object. logger.info('signal/callback: Triggered by client (%s:%s): (%r,%r)', sender, sender_path, parameter1, parameter2) tested_things.add(INTERFACE_SIGNAL_TESTS + '.Trigger') dbus.Interface(dbus.SessionBus().get_object(sender, sender_path), INTERFACE_CALLBACK_TESTS).Response( parameter1, parameter2) logger.info('signal/callback: Sent Response') if __name__ == '__main__': bus = SessionBus() bus_name = BusName(CROSS_TEST_BUS_NAME, bus=bus) loop = gobject.MainLoop() obj = Server(bus_name, CROSS_TEST_PATH, loop.quit) objects[CROSS_TEST_PATH] = obj bus.add_signal_receiver(obj.triggered_by_client, signal_name='Trigger', dbus_interface=INTERFACE_SIGNAL_TESTS, named_service=None, path=None, sender_keyword='sender', path_keyword='sender_path', utf8_strings=True) logger.info("running...") loop.run()
def __init__(self, args, read_pipe): QApplication.__init__(self, args) self.menu = None self.read_pipe = read_pipe self.fmt = "80s80sI32sI80sf" self.fmt_size = struct.calcsize(self.fmt) self.timer_active = False self.active_icon = False self.user_settings = UserSettings() self.user_settings.load() self.user_settings.debug() self.tray_icon = QSystemTrayIcon() pm = load_pixmap("hp_logo", "32x32") self.prop_icon = QIcon(pm) a = load_pixmap('active', '16x16') painter = QPainter(pm) painter.drawPixmap(32, 0, a) painter.end() self.prop_active_icon = QIcon(pm) self.tray_icon.setIcon(self.prop_icon) self.session_bus = SessionBus() self.service = None for d in device.getSupportedCUPSDevices( back_end_filter=['hp', 'hpfax']): self.addDevice(d) self.tray_icon.setToolTip(self.__tr("HPLIP Status Service")) # QObject.tray_icon.messageClicked.connect(self.messageClicked) self.tray_icon.messageClicked.connect(self.messageClicked) notifier = QSocketNotifier(self.read_pipe, QSocketNotifier.Read) # QObject.notifier.activated[int].connect(self.notifierActivated) notifier.activated[int].connect(self.notifierActivated) # QObject.tray_icon.activated[QSystemTrayIcon::ActivationReason].connect(self.trayActivated) self.tray_icon.activated["QSystemTrayIcon::ActivationReason"].connect( self.trayActivated) signal.signal(signal.SIGINT, signal.SIG_DFL) self.tray_icon.show() if self.user_settings.systray_visible == SYSTRAY_VISIBLE_SHOW_ALWAYS: self.tray_icon.setVisible(True) else: QTimer.singleShot( HIDE_INACTIVE_DELAY, self.timeoutHideWhenInactive) # show icon for awhile @ startup self.tray_icon.setIcon(self.prop_active_icon) self.active_icon = True if "--ignore-update-firsttime" not in args: self.handle_hplip_updation() QTimer.singleShot(SET_MENU_DELAY, self.initDone) self.update_timer = QTimer() # self.update_timer.connect(self.update_timer,SIGNAL("timeout()"),self.handle_hplip_updation) self.update_timer.timeout.connect(self.handle_hplip_updation) self.update_timer.start(UPGRADE_CHECK_DELAY)
XLIB_PRESENT = True #: Indicates whether python-xlib was found except ImportError: XLIB_PRESENT = False #: Indicates whether python-xlib was found DBUS_PRESENT = False try: import dbus.service from dbus import SessionBus from dbus.exceptions import DBusException from dbus.mainloop.glib import DBusGMainLoop except ImportError: pass else: try: DBusGMainLoop(set_as_default=True) sessBus = SessionBus() except DBusException: pass else: DBUS_PRESENT = True XDG_CONFIG_DIR = os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')) #TODO: Figure out how best to put this in the config file. POSITIONS = { 'left': ((0, 0, 0.5, 1), (0, 0, 1.0 / 3, 1), (0, 0, 1.0 / 3 * 2, 1)), 'middle': ((0, 0, 1, 1), (1.0 / 3, 0, 1.0 / 3, 1), (1.0 / 6, 0, 1.0 / 3 * 2, 1)), 'right': ((0.5, 0, 0.5, 1), (1.0 / 3 * 2, 0, 1.0 / 3, 1), (1.0 / 3, 0, 1.0 / 3 * 2, 1)),
def __init__(self, uid): bus_name = BusName('.'.join([DBUS_NS, uid]), bus=SessionBus()) self.dbus_uid = uid self.dbus_path = '/vim' dbus.service.Object.__init__(self, bus_name, self.dbus_path)
def post_config_hook(self): if self.py3.is_gevent(): raise Exception(STRING_GEVENT) self._name_owner_change_match = None self._kill = False self._mpris_players: dict[Player] = {} self._identity_cache = {} self._identity_index = {} self._priority_cache = {} self._player: [Player, None] = None self._tries = 0 self._empty_response = { "album": None, "artist": None, "length": None, "title": None, "nowplaying": None, "time": None, "state": None, "player": None, # for debugging ;p "full_name": None, } self._states = { "pause": { "action": "Pause", "clickable": "CanPause", "icon": self.icon_pause, "inactive": [STATE.Stopped, STATE.Paused], }, "play": { "action": "Play", "clickable": "CanPlay", "icon": self.icon_play, "inactive": [STATE.Playing], }, "stop": { "action": "Stop", "clickable": "CanControl", "icon": self.icon_stop, "inactive": [STATE.Stopped], }, "next": { "action": "Next", "clickable": "CanGoNext", "icon": self.icon_next, }, "previous": { "action": "Previous", "clickable": "CanGoPrevious", "icon": self.icon_previous, }, "toggle": { "action": "PlayPause", "clickable": "CanPause", # Not used, but it will be set dynamically with player state map. "icon": None, }, } self._state_icon_color_map = { STATE.Playing: { "state_icon": self.state_play, "color": self.py3.COLOR_PLAYING or self.py3.COLOR_GOOD, "toggle_icon": self.state_pause, "cached_until": self.cache_timeout, }, STATE.Paused: { "state_icon": self.state_pause, "color": self.py3.COLOR_PAUSED or self.py3.COLOR_DEGRADED, "toggle_icon": self.state_play, "cached_until": self.py3.CACHE_FOREVER, }, STATE.Stopped: { "state_icon": self.state_stop, "color": self.py3.COLOR_STOPPED or self.py3.COLOR_BAD, "toggle_icon": self.state_play, "cached_until": self.py3.CACHE_FOREVER, }, } self._color_active = self.py3.COLOR_CONTROL_ACTIVE or self.py3.COLOR_GOOD self._color_inactive = self.py3.COLOR_CONTROL_INACTIVE or self.py3.COLOR_BAD self._format_contains_metadata = False self._metadata_keys = ["album", "artist", "title", "nowplaying", "length"] for key in self._metadata_keys: if self.py3.format_contains(self.format, key): self._format_contains_metadata = True break self._format_contains_control_buttons = False self._used_can_properties = [] for key, value in self._states.items(): if self.py3.format_contains(self.format, key): self._format_contains_control_buttons = True self._used_can_properties.append(value["clickable"]) if ( len(self.player_hide_non_canplay) and "CanPlay" not in self._used_can_properties ): self._used_can_properties.append("CanPlay") self._format_contains_time = self.py3.format_contains(self.format, "time") self._button_cache_flush = None if 2 not in [ self.button_next, self.button_next_player, self.button_prev_player, self.button_previous, self.button_stop, self.button_switch_to_top_player, self.button_toggle, ]: self._button_cache_flush = 2 if self.player_priority: try: self._random_player_priority = self.player_priority.index("*") except ValueError: self._random_player_priority = False else: self._random_player_priority = 0 # start last self._dbus_loop = DBusGMainLoop() self._dbus = SessionBus(mainloop=self._dbus_loop) self._start_listener()
def main(): ap = argparse.ArgumentParser() ap.add_argument('--debug', action='store_true') ap.add_argument('--sound', dest='sound_spec', action='append', help='registers a sound for a specific filter with format <filter-name>:<file-path> or use format <file-path> for everything') ap.add_argument('--filter', dest='filters', action='append', choices=FILTERS.keys()) ap.add_argument('--player', default=DEFAULT_PLAYER) ap.add_argument('--rate-ms', type=int, default=DEFAULT_RATE_MS) params = ap.parse_args() logging.basicConfig( datefmt='%H:%M:%S', format='%(asctime)s %(levelname)5s - %(message)s', level='DEBUG' if params.debug else 'INFO', stream=sys.stdout, ) LOG.debug('build sound registry: %s', params.sound_spec) sounds = {'*': DEFAULT_SOUND} if params.sound_spec: for spec in params.sound_spec: spec = spec.strip() # type: str m = PATTERN_SOUNDSPEC.match(spec) if m: key = m.group('name').lower() value = m.group('path') if key not in FILTERS: ap.error('unknown filter %r in sound spec %r' % (key, spec)) return else: key = '*' value = spec if not os.access(value, os.R_OK): ap.error('audio file %r cannot be read in sound spec %r' % (value, spec)) return sounds[key] = value LOG.debug('sound registry: %s', sounds) LOG.debug('check audio player') if not os.access(params.player, os.R_OK | os.X_OK): ap.error('player %r does not exist or is not executable' % (params.player,)) LOG.debug('initialize dbus') DBusGMainLoop(set_as_default=True) bus = SessionBus() filter_keys = tuple(sorted(set(params.filters if params.filters else FILTERS.keys()))) subscribe_to_messages(bus, filter_keys) audio_player = AudioPlayer(params.player, sounds, params.rate_ms) attach_message_handler(bus, audio_player, filter_keys) LOG.info('ONLINE') loop = GLib.MainLoop() try: loop.run() except KeyboardInterrupt: loop.quit()
for s in self.__stations: for c in s.channels: for t in c.tags: tags[t] = True tags[s.id] = True tags = list(tags) tags.sort() return tags @method(dbus_interface=interface, in_signature='', out_signature='as') def ListEqualizerProfiles(self): return self.__player.get_profile_names() @method(dbus_interface=interface, in_signature='', out_signature='s') def GetEqualizerProfile(self): return self.__player.profile @method(dbus_interface=interface, in_signature='s', out_signature='') def SetEqualizerProfile(self, profile_name): self.__player.profile = profile_name if '__main__' == __name__: threads_init() DBusGMainLoop(set_as_default=True) Service(SessionBus()).run()
def makeCommandFun(clazz): return lambda _args: clazz #------------------------------------------------------------------------------ if __name__ == "__main__": mainParser = argparse.ArgumentParser( prog="jsprog", description="Command-line interface for the JSProg daemon") subParsers = mainParser.add_subparsers( title="commands", description="the commands the program accepts") for clazz in [ GetJoysticks, GetJoystickState, LoadProfile, Monitor, MonitorControls, Stop, GUI ]: parser = clazz.addParser(subParsers) parser.set_defaults(func=makeCommandFun(clazz)) args = mainParser.parse_args(sys.argv[1:]) #try: connection = SessionBus(mainloop=DBusGMainLoop()) args.func(args).execute(connection, args) #except Exception, e: # print str(e)
def quit_triggered(self): device.Event('', '', EVENT_SYSTEMTRAY_EXIT).send_via_dbus(SessionBus()) self.quit()
def send_notification(title, text, display_time): knotify = SessionBus().get_object("org.kde.knotify", "/Notify") notif = knotify.event("warning", "kde", [], title, u"%s" % text, [], [], 0, 0, dbus_interface="org.kde.KNotify") sleep(display_time) knotify.closeNotification(notif) knotify = None
def send_message(device_uri, event_code, bytes_written=0): args = [device_uri, '', event_code, prop.username, 0, '', '', bytes_written] msg = lowlevel.SignalMessage('/', 'com.hplip.StatusService', 'Event') msg.append(signature='ssisissi', *args) SessionBus().send_message(msg)
def __init__(self): session_bus = SessionBus() self.player_engine = session_bus.get_object(self.BANSHEE_OBJECT, self.PLAYER_ENGINE_NODE)
XLIB_PRESENT = True #: Indicates presence of python-xlib (runtime check) except ImportError: XLIB_PRESENT = False #: Indicates presence of python-xlib (runtime check) DBUS_PRESENT = False #: Indicates availability of D-Bus (runtime check) try: import dbus.service from dbus import SessionBus from dbus.exceptions import DBusException from dbus.mainloop.glib import DBusGMainLoop except ImportError: pass else: try: DBusGMainLoop(set_as_default=True) sessBus = SessionBus() #: D-Bus Session Bus for L{QuickTileApp.run} except DBusException: pass else: DBUS_PRESENT = True #: Indicates availability of D-Bus (runtime check) #: Location for config files (determined at runtime). XDG_CONFIG_DIR = os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')) #{ Settings class GravityLayout(object): """Helper for generating L{cycle_dimensions} presets.""" #: Possible window alignments relative to the monitor/desktop. #: @todo 1.0.0: Normalize these to X11 or CSS terminology for 1.0
class Dbus: service_name = 'org.romek.service' service_object = '/org/romek/service' interface_name = 'org.romek.interface' bus = SessionBus() @classmethod def get_temperature_status(cls): obj = cls._get_dbus_object() return obj.get_temperature_status(dbus_interface=cls.interface_name) @classmethod def get_temperature_settings(cls): obj = cls._get_dbus_object() return obj.get_temperature_settings(dbus_interface=cls.interface_name) @classmethod def set_temperature_settings(cls, settings): obj = cls._get_dbus_object() return obj.set_temperature_settings(settings, dbus_interface=cls.interface_name) @classmethod def get_manual_mode(cls): obj = cls._get_dbus_object() return obj.get_manual_mode(dbus_interface=cls.interface_name) @classmethod def set_manual_mode(cls, manual_mode): obj = cls._get_dbus_object() return obj.set_manual_mode(manual_mode, dbus_interface=cls.interface_name) @classmethod def get_schedule_list(cls): obj = cls._get_dbus_object() return obj.list_schedule_task(dbus_interface=cls.interface_name) @classmethod def add_schedule_task(cls, task): obj = cls._get_dbus_object() return obj.add_schedule_task(task, dbus_interface=cls.interface_name) @classmethod def update_schedule_task(cls, old_task, new_task): obj = cls._get_dbus_object() return obj.update_schedule_task((old_task, new_task), dbus_interface=cls.interface_name) @classmethod def remove_schedule_task(cls, task): obj = cls._get_dbus_object() return obj.remove_schedule_task(task, dbus_interface=cls.interface_name) @classmethod def get_temperature_history(cls): obj = cls._get_dbus_object() return obj.get_temperature_history(dbus_interface=cls.interface_name) @classmethod def _get_dbus_object(cls): return cls.bus.get_object(cls.service_name, cls.service_object)
base_cmd = ['amixer'] volume_type = 'Master' # Interpreting how to affect the volume and by what percentage vol_action = argv[1] if vol_action in ['increase', 'decrease']: vol_percent_change = int(argv[2]) elif vol_action in ['mute']: vol_percent_change = 0 else: print("ERROR: command not one of 'decrease', 'increase' or 'mute': {}". format(vol_action)) exit(1) # Getting the dbus interface to communicate with gnome's OSD session_bus = SessionBus() proxy = session_bus.get_object('org.gnome.Shell', '/org/gnome/Shell') interface = Interface(proxy, 'org.gnome.Shell') # Get the current state. output = check_output(base_cmd + ['sget', volume_type]).decode('utf-8') # Mute status. try: on = search(r'\[(on)?(off)?\]', output).group(1) except IndexError: print("ERROR: no volume information found, try changing base_cmd") exit(1) # Calculate the new level based on an average for all levels. vol_percentage = [int(x) for x in findall(r'\[(\d{1,3})\%\]', output)]
def send(self, body, title='', notify_type=NotifyType.INFO, **kwargs): """ Perform DBus Notification """ if not self._enabled or MAINLOOP_MAP[self.schema] is None: self.logger.warning("{} notifications could not be loaded.".format( self.schema)) return False # Acquire our session session = SessionBus(mainloop=MAINLOOP_MAP[self.schema]) # acquire our dbus object dbus_obj = session.get_object( NOTIFY_DBUS_INTERFACE, NOTIFY_DBUS_SETTING_LOCATION, ) # Acquire our dbus interface dbus_iface = Interface( dbus_obj, dbus_interface=NOTIFY_DBUS_INTERFACE, ) # image path icon_path = None if not self.include_image \ else self.image_path(notify_type, extension='.ico') # Our meta payload meta_payload = {"urgency": Byte(self.urgency)} if not (self.x_axis is None and self.y_axis is None): # Set x/y access if these were set meta_payload['x'] = self.x_axis meta_payload['y'] = self.y_axis if NOTIFY_DBUS_IMAGE_SUPPORT and icon_path: try: # Use Pixbuf to create the proper image type image = GdkPixbuf.Pixbuf.new_from_file(icon_path) # Associate our image to our notification meta_payload['icon_data'] = (image.get_width(), image.get_height(), image.get_rowstride(), image.get_has_alpha(), image.get_bits_per_sample(), image.get_n_channels(), ByteArray(image.get_pixels())) except Exception as e: self.logger.warning( "Could not load Gnome notification icon ({}): {}".format( icon_path, e)) try: # Always call throttle() before any remote execution is made self.throttle() dbus_iface.Notify( # Application Identifier self.app_id, # Message ID (0 = New Message) 0, # Icon (str) - not used '', # Title str(title), # Body str(body), # Actions list(), # Meta meta_payload, # Message Timeout self.message_timeout_ms, ) self.logger.info('Sent DBus notification.') except Exception: self.logger.warning('Failed to send DBus notification.') self.logger.exception('DBus Exception') return False return True
def main(self, argv=None, standalone=None, plugin_argument_provider=None, plugin_manager_settings_prefix=''): if argv is None: argv = sys.argv # extract --args and everything behind manually since argparse can not handle that arguments = argv[1:] # extract plugin specific args when not being invoked in standalone mode programmatically if not standalone: plugin_args = [] if '--args' in arguments: index = arguments.index('--args') plugin_args = arguments[index + 1:] arguments = arguments[0:index + 1] parser = ArgumentParser(os.path.basename(Main.main_filename), add_help=False) self.add_arguments(parser, standalone=bool(standalone), plugin_argument_provider=plugin_argument_provider) self._options = parser.parse_args(arguments) if standalone: # rerun parsing to separate common arguments from plugin specific arguments parser = ArgumentParser(os.path.basename(Main.main_filename), add_help=False) self.add_arguments(parser, standalone=bool(standalone)) self._options, plugin_args = parser.parse_known_args(arguments) self._options.plugin_args = plugin_args # set default values for options not available in standalone mode if standalone: self._options.freeze_layout = False self._options.lock_perspective = False self._options.multi_process = False self._options.perspective = None self._options.perspective_file = None self._options.standalone_plugin = standalone self._options.list_perspectives = False self._options.list_plugins = False self._options.command_pid = None self._options.command_start_plugin = None self._options.command_switch_perspective = None self._options.embed_plugin = None self._options.embed_plugin_serial = None self._options.embed_plugin_address = None # check option dependencies try: if self._options.plugin_args and not self._options.standalone_plugin and not self._options.command_start_plugin and not self._options.embed_plugin: raise RuntimeError( 'Option --args can only be used together with either --standalone, --command-start-plugin or --embed-plugin option' ) if self._options.freeze_layout and not self._options.lock_perspective: raise RuntimeError( 'Option --freeze_layout can only be used together with the --lock_perspective option' ) list_options = (self._options.list_perspectives, self._options.list_plugins) list_options_set = [ opt for opt in list_options if opt is not False ] if len(list_options_set) > 1: raise RuntimeError( 'Only one --list-* option can be used at a time') command_options = (self._options.command_start_plugin, self._options.command_switch_perspective) command_options_set = [ opt for opt in command_options if opt is not None ] if len(command_options_set) > 0 and not self._dbus_available: raise RuntimeError( 'Without DBus support the --command-* options are not available' ) if len(command_options_set) > 1: raise RuntimeError( 'Only one --command-* option can be used at a time (except --command-pid which is optional)' ) if len(command_options_set ) == 0 and self._options.command_pid is not None: raise RuntimeError( 'Option --command_pid can only be used together with an other --command-* option' ) embed_options = (self._options.embed_plugin, self._options.embed_plugin_serial, self._options.embed_plugin_address) embed_options_set = [ opt for opt in embed_options if opt is not None ] if len(command_options_set) > 0 and not self._dbus_available: raise RuntimeError( 'Without DBus support the --embed-* options are not available' ) if len(embed_options_set) > 0 and len(embed_options_set) < len( embed_options): raise RuntimeError( 'Missing option(s) - all \'--embed-*\' options must be set' ) if len(embed_options_set) > 0 and self._options.clear_config: raise RuntimeError( 'Option --clear-config can only be used without any --embed-* option' ) groups = (list_options_set, command_options_set, embed_options_set) groups_set = [opt for opt in groups if len(opt) > 0] if len(groups_set) > 1: raise RuntimeError( 'Options from different groups (--list, --command, --embed) can not be used together' ) perspective_options = (self._options.perspective, self._options.perspective_file) perspective_options_set = [ opt for opt in perspective_options if opt is not None ] if len(perspective_options_set) > 1: raise RuntimeError( 'Only one --perspective-* option can be used at a time') if self._options.perspective_file is not None and not os.path.isfile( self._options.perspective_file): raise RuntimeError( 'Option --perspective-file must reference existing file') except RuntimeError as e: print(str(e)) #parser.parse_args(['--help']) # calling --help will exit return 1 # set implicit option dependencies if self._options.standalone_plugin is not None: self._options.lock_perspective = True # create application context containing various relevant information from .application_context import ApplicationContext context = ApplicationContext() context.qtgui_path = self._qtgui_path context.options = self._options if self._dbus_available: from dbus import DBusException, Interface, SessionBus # non-special applications provide various dbus interfaces if self._dbus_available: context.provide_app_dbus_interfaces = len(groups_set) == 0 context.dbus_base_bus_name = 'org.ros.qt_gui' if context.provide_app_dbus_interfaces: context.dbus_unique_bus_name = context.dbus_base_bus_name + '.pid%d' % os.getpid( ) # provide pid of application via dbus from .application_dbus_interface import ApplicationDBusInterface _dbus_server = ApplicationDBusInterface( context.dbus_base_bus_name) # determine host bus name, either based on pid given on command line or via dbus application interface if any other instance is available if len(command_options_set) > 0 or len(embed_options_set) > 0: host_pid = None if self._options.command_pid is not None: host_pid = self._options.command_pid else: try: remote_object = SessionBus().get_object( context.dbus_base_bus_name, '/Application') except DBusException: pass else: remote_interface = Interface( remote_object, context.dbus_base_bus_name + '.Application') host_pid = remote_interface.get_pid() if host_pid is not None: context.dbus_host_bus_name = context.dbus_base_bus_name + '.pid%d' % host_pid # execute command on host application instance if len(command_options_set) > 0: if self._options.command_start_plugin is not None: try: remote_object = SessionBus().get_object( context.dbus_host_bus_name, '/PluginManager') except DBusException: (rc, msg) = (1, 'unable to communicate with GUI instance "%s"' % context.dbus_host_bus_name) else: remote_interface = Interface( remote_object, context.dbus_base_bus_name + '.PluginManager') (rc, msg) = remote_interface.start_plugin( self._options.command_start_plugin, ' '.join(self._options.plugin_args)) if rc == 0: print('qt_gui_main() started plugin "%s" in GUI "%s"' % (msg, context.dbus_host_bus_name)) else: print( 'qt_gui_main() could not start plugin "%s" in GUI "%s": %s' % (self._options.command_start_plugin, context.dbus_host_bus_name, msg)) return rc elif self._options.command_switch_perspective is not None: remote_object = SessionBus().get_object( context.dbus_host_bus_name, '/PerspectiveManager') remote_interface = Interface( remote_object, context.dbus_base_bus_name + '.PerspectiveManager') remote_interface.switch_perspective( self._options.command_switch_perspective) print( 'qt_gui_main() switched to perspective "%s" in GUI "%s"' % (self._options.command_switch_perspective, context.dbus_host_bus_name)) return 0 raise RuntimeError('Unknown command not handled') # choose selected or default qt binding setattr(sys, 'SELECT_QT_BINDING', self._options.qt_binding) from python_qt_binding import QT_BINDING from python_qt_binding.QtCore import qDebug, qInstallMsgHandler, QSettings, Qt, QtCriticalMsg, QtDebugMsg, QtFatalMsg, QTimer, QtWarningMsg from python_qt_binding.QtGui import QAction, QIcon, QMenuBar from .about_handler import AboutHandler from .composite_plugin_provider import CompositePluginProvider from .container_manager import ContainerManager from .help_provider import HelpProvider from .main_window import MainWindow from .minimized_dock_widgets_toolbar import MinimizedDockWidgetsToolbar from .perspective_manager import PerspectiveManager from .plugin_manager import PluginManager def message_handler(type_, msg): colored_output = 'TERM' in os.environ and 'ANSI_COLORS_DISABLED' not in os.environ cyan_color = '\033[36m' if colored_output else '' red_color = '\033[31m' if colored_output else '' reset_color = '\033[0m' if colored_output else '' if type_ == QtDebugMsg and self._options.verbose: print(msg, file=sys.stderr) elif type_ == QtWarningMsg: print(cyan_color + msg + reset_color, file=sys.stderr) elif type_ == QtCriticalMsg: print(red_color + msg + reset_color, file=sys.stderr) elif type_ == QtFatalMsg: print(red_color + msg + reset_color, file=sys.stderr) sys.exit(1) qInstallMsgHandler(message_handler) app = self.create_application(argv) self._check_icon_theme_compliance() settings = QSettings(QSettings.IniFormat, QSettings.UserScope, 'ros.org', self._settings_filename) if len(embed_options_set) == 0: if self._options.clear_config: settings.clear() main_window = MainWindow() if self._options.on_top: main_window.setWindowFlags(Qt.WindowStaysOnTopHint) main_window.statusBar() def sigint_handler(*args): qDebug('\nsigint_handler()') main_window.close() signal.signal(signal.SIGINT, sigint_handler) # the timer enables triggering the sigint_handler timer = QTimer() timer.start(500) timer.timeout.connect(lambda: None) # create own menu bar to share one menu bar on Mac menu_bar = QMenuBar() if 'darwin' in platform.platform().lower(): menu_bar.setNativeMenuBar(True) else: menu_bar.setNativeMenuBar(False) if not self._options.lock_perspective: main_window.setMenuBar(menu_bar) file_menu = menu_bar.addMenu(menu_bar.tr('&File')) action = QAction(file_menu.tr('&Quit'), file_menu) action.setIcon(QIcon.fromTheme('application-exit')) action.triggered.connect(main_window.close) file_menu.addAction(action) else: app.setQuitOnLastWindowClosed(False) main_window = None menu_bar = None self._add_plugin_providers() # setup plugin manager plugin_provider = CompositePluginProvider(self.plugin_providers) plugin_manager = PluginManager( plugin_provider, settings, context, settings_prefix=plugin_manager_settings_prefix) if self._options.list_plugins: # output available plugins print('\n'.join(sorted(plugin_manager.get_plugins().values()))) return 0 help_provider = HelpProvider() plugin_manager.plugin_help_signal.connect( help_provider.plugin_help_request) # setup perspective manager if main_window is not None: perspective_manager = PerspectiveManager(settings, context) if self._options.list_perspectives: # output available perspectives print('\n'.join(sorted(perspective_manager.perspectives))) return 0 else: perspective_manager = None if main_window is not None: container_manager = ContainerManager(main_window, plugin_manager) plugin_manager.set_main_window(main_window, menu_bar, container_manager) if not self._options.freeze_layout: minimized_dock_widgets_toolbar = MinimizedDockWidgetsToolbar( container_manager, main_window) main_window.addToolBar(Qt.BottomToolBarArea, minimized_dock_widgets_toolbar) plugin_manager.set_minimized_dock_widgets_toolbar( minimized_dock_widgets_toolbar) if menu_bar is not None: perspective_menu = menu_bar.addMenu(menu_bar.tr('P&erspectives')) perspective_manager.set_menu(perspective_menu) # connect various signals and slots if perspective_manager is not None and main_window is not None: # signal changed perspective to update window title perspective_manager.perspective_changed_signal.connect( main_window.perspective_changed) # signal new settings due to changed perspective perspective_manager.save_settings_signal.connect( main_window.save_settings) perspective_manager.restore_settings_signal.connect( main_window.restore_settings) perspective_manager.restore_settings_without_plugin_changes_signal.connect( main_window.restore_settings) if perspective_manager is not None and plugin_manager is not None: perspective_manager.save_settings_signal.connect( plugin_manager.save_settings) plugin_manager.save_settings_completed_signal.connect( perspective_manager.save_settings_completed) perspective_manager.restore_settings_signal.connect( plugin_manager.restore_settings) perspective_manager.restore_settings_without_plugin_changes_signal.connect( plugin_manager.restore_settings_without_plugins) if plugin_manager is not None and main_window is not None: # signal before changing plugins to save window state plugin_manager.plugins_about_to_change_signal.connect( main_window.save_setup) # signal changed plugins to restore window state plugin_manager.plugins_changed_signal.connect( main_window.restore_state) # signal save settings to store plugin setup on close main_window.save_settings_before_close_signal.connect( plugin_manager.close_application) # signal save and shutdown called for all plugins, trigger closing main window again plugin_manager.close_application_signal.connect( main_window.close, type=Qt.QueuedConnection) if main_window is not None and menu_bar is not None: about_handler = AboutHandler(context.qtgui_path, main_window) help_menu = menu_bar.addMenu(menu_bar.tr('&Help')) action = QAction(file_menu.tr('&About'), help_menu) action.setIcon(QIcon.fromTheme('help-about')) action.triggered.connect(about_handler.show) help_menu.addAction(action) # set initial size - only used without saved configuration if main_window is not None: main_window.resize(600, 450) main_window.move(100, 100) # ensure that qt_gui/src is in sys.path src_path = os.path.realpath( os.path.join(os.path.dirname(__file__), '..')) if src_path not in sys.path: sys.path.append(src_path) # load specific plugin plugin = None plugin_serial = None if self._options.embed_plugin is not None: plugin = self._options.embed_plugin plugin_serial = self._options.embed_plugin_serial elif self._options.standalone_plugin is not None: plugin = self._options.standalone_plugin plugin_serial = 0 if plugin is not None: plugins = plugin_manager.find_plugins_by_name(plugin) if len(plugins) == 0: print('qt_gui_main() found no plugin matching "%s"' % plugin) return 1 elif len(plugins) > 1: print( 'qt_gui_main() found multiple plugins matching "%s"\n%s' % (plugin, '\n'.join(plugins.values()))) return 1 plugin = plugins.keys()[0] qDebug('QtBindingHelper using %s' % QT_BINDING) plugin_manager.discover() if self._options.reload_import: qDebug( 'ReloadImporter() automatically reload all subsequent imports') from .reload_importer import ReloadImporter _reload_importer = ReloadImporter() self._add_reload_paths(_reload_importer) _reload_importer.enable() # switch perspective if perspective_manager is not None: if plugin: perspective_manager.set_perspective( plugin, hide_and_without_plugin_changes=True) elif self._options.perspective_file: perspective_manager.import_perspective_from_file( self._options.perspective_file, perspective_manager.HIDDEN_PREFIX + '__cli_perspective_from_file') else: perspective_manager.set_perspective(self._options.perspective) # load specific plugin if plugin: plugin_manager.load_plugin(plugin, plugin_serial, self._options.plugin_args) running = plugin_manager.is_plugin_running(plugin, plugin_serial) if not running: return 1 if main_window is not None: main_window.show() if sys.platform == 'darwin': main_window.raise_() return app.exec_()
def __init__(self): super(Client, self).__init__() self.__stations = dict() self.__channels = dict() self.__stream_tags = dict() self.__current_channel = None self.__is_playing = False def register_channel(station, channel): if station: station.channels.append(channel) for stream in channel.streams: self.__channels[stream.uri] = channel self.__channels[channel.uri] = channel def station_added_cb(station): id, title, uri, channels = station station = Station(id, title, uri) for channel in channels: channel = self.decode_channel(station, *channel) register_channel(station, channel) self.__stations[station.id] = station self.emit('station-added', station) def channel_added_cb(station_id, channel): station = self.find_station(station_id) channel = self.decode_channel(station, *channel) register_channel(station, channel) self.emit('channel-added', channel) def state_changed_cb(playing, stream_uri): self.__stream_tags = self.__service.GetStreamTags() self.__current_channel = self.__channels.get(stream_uri) self.__is_playing = playing self.emit('state-changed') def stream_tags_changed_cb(tags): self.__stream_tags.update(tags) self.emit('stream-tags-changed') def name_owner_cb(new_owner): if not new_owner: # FIXME from gtk import main_quit main_quit() self.__bus = SessionBus() proxy = self.__bus.get_object(Service.name, '/') self.__bus.watch_name_owner(Service.name, name_owner_cb) self.__service = Interface(proxy, Service.interface) self.__service.connect_to_signal('StationAdded', station_added_cb) self.__service.connect_to_signal('ChannelAdded', channel_added_cb) self.__service.connect_to_signal('StateChanged', state_changed_cb) self.__service.connect_to_signal('StreamTagsChanged', stream_tags_changed_cb) for station in self.__service.GetStations(): station_added_cb(station) state_changed_cb(*self.__service.GetState())