def remote_gateway_name(): ''' Assumption: note that the remote gateway info in the paired master system should only ever show at most, one remote gateway. That should be the private counterpart (we're not using zeroconf over here). @return namespace of the app manager (matches the remote gateway name) @rtype string or None : string does not yet prefix a leading '/' ''' remote_gateway_info_service = rospy.ServiceProxy( '~remote_gateway_info', gateway_srvs.RemoteGatewayInfo) remote_gateway_name = None while not rospy.is_shutdown(): try: rospy.wait_for_service('~remote_gateway_info', timeout=0.3) except rospy.exceptions.ROSException: # timeout exceeded continue except (rospy.exceptions.ROSInterruptException, rospy.service.ServiceException): # shutdown exception sys.exit(0) remote_gateway_info = remote_gateway_info_service() if len(remote_gateway_info.gateways) == 1: remote_gateway_name = remote_gateway_info.gateways[0].name break elif len(remote_gateway_info.gateways) == 2: console.error( "Pairing Master : found two remote gateways when there should only ever be one." ) sys.exit(1) if remote_gateway_name is None: # probably shutting down #console.error("Pairing Master : app_manager_namespace returned 'None', probably shutting down.") sys.exit(0) return remote_gateway_name
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 __init__(self, terminal_name, hold=False): """ Initialise empty of processes, but configure a terminal so we're ready to go when we start spawning. :param str terminal_name: string name (or None) for the terminal to use. :param bool hold: whether or not to hold windows open or not. """ self.processes = [] """List of spawned :class:`subprocess.Popen` terminal processes.""" self.temporary_files = [] """List of temporary files used to construct launches that we must unlink before finishing.""" self.hold = hold try: self.terminal = terminals.create_terminal(terminal_name) except (UnsupportedTerminal, rocon_python_comms.NotFoundException) as e: console.error("Cannot find a suitable terminal [%s]" % str(e)) sys.exit(1)
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
def _process_arg_tag(tag, args_dict=None): ''' Process the arg tag. Kind of hate replicating what roslaunch does with arg tags, but there's no easy way to pull roslaunch code. @param args_dict : dictionary of args previously discovered ''' name = tag.get('name') # returns None if not found. if name is None: console.error("<arg> tag must have a name attribute.") sys.exit(1) value = tag.get('value') default = tag.get('default') #print("Arg tag processing: (%s, %s, %s)" % (name, value, default)) if value is not None and default is not None: console.error( "<arg> tag must have one and only one of value/default attributes specified." ) sys.exit(1) if value is None and default is None: console.error( "<arg> tag must have one of value/default attributes specified.") sys.exit(1) if value is None: value = default if value and '$' in value: value = roslaunch.substitution_args.resolve_args(value, args_dict) return (name, value)
def main(): global processes global roslaunch_pids signal.signal(signal.SIGINT, signal_handler) args = parse_arguments() terminal = None if not args.no_terminals: if not rocon_python_utils.system.which( 'konsole') and not rocon_python_utils.system.which( 'gnome-terminal') and not rocon_python_utils.system.which( 'x-terminal-emulator'): console.error( "Cannot find a suitable terminal [x-terminal-emulator, konsole, gnome-termional]" ) sys.exit(1) terminal = choose_terminal(args.gnome, args.konsole) if args.package == '': rocon_launcher = roslaunch.rlutil.resolve_launch_arguments( args.launcher)[0] else: rocon_launcher = roslaunch.rlutil.resolve_launch_arguments( [args.package] + args.launcher)[0] if args.screen: roslaunch_options = "--screen" else: roslaunch_options = "" launchers = parse_rocon_launcher(rocon_launcher, roslaunch_options) temporary_launchers = [] for launcher in launchers: console.pretty_println( "Launching [%s, %s] on port %s" % (launcher['package'], launcher['name'], launcher['port']), console.bold) ########################## # Customise the launcher ########################## temp = tempfile.NamedTemporaryFile(mode='w+t', delete=False) print("Launching %s" % temp.name) launcher_filename = rocon_python_utils.ros.find_resource( launcher['package'], launcher['name']) launch_text = '<launch>\n' if args.screen: launch_text += ' <param name="rocon/screen" value="true"/>\n' else: launch_text += ' <param name="rocon/screen" value="false"/>\n' launch_text += ' <include file="%s">\n' % launcher_filename for (arg_name, arg_value) in launcher['args']: launch_text += ' <arg name="%s" value="%s"/>\n' % (arg_name, arg_value) launch_text += ' </include>\n' launch_text += '</launch>\n' #print launch_text temp.write(launch_text) temp.close() # unlink it later temporary_launchers.append(temp) ########################## # Start the terminal ########################## if terminal == 'konsole': p = subprocess.Popen([ terminal, '-p', 'tabtitle=%s' % launcher['title'], '--nofork', '--hold', '-e', "/bin/bash", "-c", "roslaunch %s --disable-title --port %s %s" % (launcher['options'], launcher['port'], temp.name) ], preexec_fn=preexec) elif terminal == 'gnome-terminal.wrapper' or terminal == 'gnome-terminal': # --disable-factory inherits the current environment, bit wierd. cmd = [ 'gnome-terminal', '--title=%s' % launcher['title'], '--disable-factory', "-e", "/bin/bash -c 'roslaunch %s --disable-title --port %s %s';/bin/bash" % (launcher['options'], launcher['port'], temp.name) ] p = subprocess.Popen(cmd, preexec_fn=preexec) else: cmd = ["roslaunch"] if launcher['options']: cmd.append(launcher['options']) cmd.extend(["--port", launcher['port'], temp.name]) p = subprocess.Popen(cmd, preexec_fn=preexec) processes.append(p) signal.pause() # Have to unlink them here rather than in the for loop above, because the whole gnome-terminal # subprocess takes a while to kick in (in the background) and the unlinking may occur before # it actually runs the roslaunch that needs the file. for temporary_launcher in temporary_launchers: os.unlink(temporary_launcher.name)