def shutdown_roslaunch_windows(self, processes, hold): """ Shuts down a roslaunch window cleanly, i.e. it first kills the roslaunch processes, then kills the terminal itself. """ roslaunch_pids = [] for process in processes: roslaunch_pids.extend(utils.get_roslaunch_pids(process.pid)) # kill roslaunch's for pid in roslaunch_pids: try: os.kill(pid, signal.SIGHUP) except OSError: continue for pid in roslaunch_pids: console.pretty_println("Terminating roslaunch [pid: %d]" % pid, console.bold) rocon_python_utils.system.wait_pid(pid) #console.pretty_println("Terminated roslaunch [pid: %d]" % pid, console.bold) time.sleep(1) if hold: try: raw_input("Press <Enter> to close terminals...") except RuntimeError: pass # this happens when you ctrl-c again instead of enter # now kill the terminal itself for process in processes: try: os.killpg(process.pid, signal.SIGTERM) except OSError: console.warning("Kill signal failed to reach the terminal - typically this means the terminal has already shut down.") except TypeError as e: console.error("Invalid pid value [%s][%s]" % (str(process.pid), str(e)))
def create_terminal(name=None): """ Creates a manager for the terminal with supporting methods and variables. If name is None, it will try to auto-detect the user's terminal. We're currently using ubuntu's x-terminal-emulator to choose the shell. :param str name: name of the terminal manager to create (None to auto-detect). :returns: one of the suported terminal classes :rtype: one of the children of :class:.`.Terminal` :raises :exc:`.UnsupportedTerminal` if the name is not in the supported terminals list. :raises :exc:`rocon_python_comms.NotFoundException` if the specified/auto-detected terminal is not found on the system. """ if name is not None and name not in supported_terminals.keys(): raise UnsupportedTerminal("%s is not a supported terminal type [%s]" % (name, supported_terminals.keys())) if name == konsole: if not rocon_python_utils.system.which('konsole'): msg = "cannot find 'konsole' (hint: try --gnome for gnome-terminal instead)" raise rocon_python_comms.NotFoundException(msg) elif name == gnome_terminal or name == gnome_terminal_wrapper: if not rocon_python_utils.system.which('konsole'): msg = "cannot find 'gnome' (hint: try --konsole for konsole instead)" raise rocon_python_comms.NotFoundException(msg) # elif name is active: # nothing to do elif name is None: # auto-detect if not rocon_python_utils.system.which('x-terminal-emulator'): msg = "tried to auto-detect, but cannot find 'x-terminal-emulator' (hint: try --gnome or --konsole instead)" raise rocon_python_comms.NotFoundException(msg) p = subprocess.Popen([ rocon_python_utils.system.which('update-alternatives'), '--query', 'x-terminal-emulator' ], stdout=subprocess.PIPE) for line in p.stdout: if line.startswith("Value:"): auto_detected_name = os.path.basename(line.split()[1]) break if auto_detected_name not in supported_terminals.keys(): msg = "you are %s, an esoteric and unsupported terminal" % ( auto_detected_name) console.warning(msg.capitalize()) fallbacks = [konsole, gnome_terminal] for terminal_name in fallbacks: if rocon_python_utils.system.which(terminal_name): name = terminal_name console.warning(" --> falling back to '%s'" % terminal_name) if name is None: raise UnsupportedTerminal( msg + " (hint: try --gnome or --konsole instead)[%s]" % supported_terminals.keys()) else: name = auto_detected_name return supported_terminals[name]()
def __init__(self, ros_master_uri, host_name): super(InteractionsRemocon, self).__init__() self.key = uuid.uuid4() self.ros_master_uri = ros_master_uri self.ros_master_port = urlparse(self.ros_master_uri).port self.host_name = host_name self.name = "rqt_remocon_" + self.key.hex console.loginfo("Connection Details") console.loginfo(" Node Name: " + self.name) console.loginfo(" ROS_MASTER_URI: " + self.ros_master_uri) console.loginfo(" ROS_HOSTNAME: " + self.host_name) self.launched_interactions = LaunchedInteractions() # terminal for roslaunchers and other shell executables try: self.roslaunch_terminal = rocon_launch.create_terminal() except (rocon_launch.UnsupportedTerminal, rocon_python_comms.NotFoundException) as e: console.warning( "Cannot find a suitable terminal, falling back to the current terminal [%s]" % str(e)) self.roslaunch_terminal = rocon_launch.create_terminal( rocon_launch.terminals.active) self.namespaces = [] self.active_namespace = None self.rocon_uri = "rocon:/" self.active_pairing = None self.active_paired_interaction_hashes = [] # TODO a configurable icon...with a default self.platform_info = rocon_std_msgs.MasterInfo( version=rocon_std_msgs.Strings.ROCON_VERSION, rocon_uri=str(self.rocon_uri), icon=rocon_std_msgs.Icon(), description="") self.service_proxies = None self.subscribers = None self.pairings_table = get_pairings(self.active_namespace) self.interactions_table = get_interactions(self.active_namespace, "rocon:/") self.namespace_scanner = NamespaceScanner() self.namespace_scanner.signal_updated.connect(self.interactions_found, Qt.QueuedConnection) # self.namespace_scanner.busy_dialog.show() self.namespace_scanner.start() self.remocon_status_publisher = rospy.Publisher( "/remocons/" + self.name, interaction_msgs.RemoconStatus, latch=True, queue_size=5) self._publish_remocon_status()
def get_roslaunch_pids(parent_pid): ''' Search the pstree of the specified pid for roslaunch processes. We use this to aid in gracefully terminating any roslaunch processes running in terminals before closing down the terminals themselves. :param str parent_pid: the pid of the parent process. :returns: list of pids :rtype: str[] ''' if parent_pid is None: console.warning( "aborting call to find child roslaunches of a non-existant parent pid (can happen if cancelling spawned processes while they are still establishing)." ) return [] ps_command = subprocess.Popen("ps -o pid -o comm --ppid %d --noheaders" % parent_pid, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) ps_output = ps_command.stdout.read() retcode = ps_command.wait() pids = [] if retcode == 0: for pair in ps_output.split("\n")[:-1]: try: [pid, command] = pair.lstrip(' ').split(" ") except ValueError: # when we can't unpack the output into two pieces # ignore, it's not a roslaunch console.warning( "Rocon Launch : bad pair while scanning for roslaunch pids [%s]" % pair) continue if command == 'roslaunch': pids.append(int(pid)) else: pids.extend(get_roslaunch_pids(int(pid))) else: # Presume this roslaunch was killed by ctrl-c or terminated already. # Am not worrying about classifying between the above presumption and real errors for now pass return pids
def __init__(self, stop_interaction_postexec_fn): ''' @param stop_app_postexec_fn : callback to fire when a listener detects an app getting stopped. @type method with no args ''' self._interactions_table = InteractionsTable() self._stop_interaction_postexec_fn = stop_interaction_postexec_fn self.is_connect = False self.key = uuid.uuid4() self._ros_master_port = None try: self._roslaunch_terminal = rocon_launch.create_terminal() except (rocon_launch.UnsupportedTerminal, rocon_python_comms.NotFoundException) as e: console.warning( "Cannot find a suitable terminal, falling back to the current terminal [%s]" % str(e)) self._roslaunch_terminal = rocon_launch.create_terminal( rocon_launch.terminals.active) # this might be naive and only work well on ubuntu... os_codename = OsDetect().get_codename() webbrowser_codename = utils.get_web_browser_codename() # this would be good as a persistant variable so the user can set something like 'Bob' self.name = "rqt_remocon_" + self.key.hex self.rocon_uri = rocon_uri.parse("rocon:/pc/" + self.name + "/" + rocon_std_msgs.Strings.URI_WILDCARD + "/" + os_codename + "|" + webbrowser_codename) # be also great to have a configurable icon...with a default self.platform_info = rocon_std_msgs.PlatformInfo( version=rocon_std_msgs.Strings.ROCON_VERSION, uri=str(self.rocon_uri), icon=rocon_std_msgs.Icon()) console.logdebug("Interactive Client : initialised") self.pairing = None # if an interaction is currently pairing, this will store its hash # expose underlying functionality higher up self.interactions = self._interactions_table.generate_role_view """Get a dictionary of interactions belonging to the specified role."""
def __init__(self, stop_interaction_postexec_fn): ''' @param stop_app_postexec_fn : callback to fire when a listener detects an app getting stopped. @type method with no args ''' self._interactions_table = InteractionsTable() self._stop_interaction_postexec_fn = stop_interaction_postexec_fn self.is_connect = False self.key = uuid.uuid4() self._ros_master_port = None try: self._roslaunch_terminal = rocon_launch.create_terminal() except (rocon_launch.UnsupportedTerminal, rocon_python_comms.NotFoundException) as e: console.warning( "Cannot find a suitable terminal, falling back to the current terminal [%s]" % str(e)) self._roslaunch_terminal = rocon_launch.create_terminal( rocon_launch.terminals.active) # this would be good as a persistant variable so the user can set something like 'Bob' self.name = "rqt_remocon_" + self.key.hex self.rocon_uri = rocon_uri.parse( rocon_uri.generate_platform_rocon_uri('pc', self.name) + "|" + utils.get_web_browser_codename()) # be also great to have a configurable icon...with a default self.platform_info = rocon_std_msgs.MasterInfo( version=rocon_std_msgs.Strings.ROCON_VERSION, rocon_uri=str(self.rocon_uri), icon=rocon_std_msgs.Icon(), description="") self.currently_pairing_interaction_hashes = [] self.active_one_sided_interaction = None # expose underlying functionality higher up self.interactions = self._interactions_table.generate_role_view """Get a dictionary of interactions belonging to the specified role."""
def choose_terminal(gnome_flag, konsole_flag): ''' Use ubuntu's x-terminal-emulator to choose the shell, or over-ride if it there is a flag. ''' if konsole_flag: if not rocon_python_utils.system.which('konsole'): console.error( "Cannot find 'konsole' [hint: try --gnome for gnome-terminal instead]" ) sys.exit(1) return 'konsole' elif gnome_flag: if not rocon_python_utils.system.which('gnome-terminal'): console.error( "Cannot find 'gnome' [hint: try --konsole for konsole instead]" ) sys.exit(1) return 'gnome-terminal' else: if not rocon_python_utils.system.which('x-terminal-emulator'): console.error( "Cannot find 'x-terminal-emulator' [hint: try --gnome or --konsole instead]" ) sys.exit(1) p = subprocess.Popen([ rocon_python_utils.system.which('update-alternatives'), '--query', 'x-terminal-emulator' ], stdout=subprocess.PIPE) terminal = None for line in p.stdout: if line.startswith("Value:"): terminal = os.path.basename(line.split()[1]) break if terminal not in [ "gnome-terminal", "gnome-terminal.wrapper", "konsole" ]: console.warning( "You are using an esoteric unsupported terminal [%s]" % terminal) if rocon_python_utils.system.which('konsole'): terminal = 'konsole' console.warning(" --> falling back to 'konsole'") elif rocon_python_utils.system.which('gnome-terminal'): console.warning(" --> falling back to 'gnome-terminal'") terminal = 'gnome-terminal' else: console.error( "Unsupported terminal set for 'x-terminal-emulator' [%s][hint: try --gnome or --konsole instead]" % terminal) sys.exit(1) return terminal