def expand_item(self, path, path_id, clear_cache=False): ''' Returns for the given item and path the file path if this is a file. Otherwise the folder will be expanded and None will be returned. :param str path: the real path of the item :param int path_id: the id of the path :param bool clear_cache: clear cache before reload :return: path of the launch file or None :rtype: str :raise Exception: if no path to given item was found ''' if path_id in [PathItem.NOTHING]: return None has_shift_mod = Qt.ShiftModifier & QApplication.keyboardModifiers() if path_id in [ PathItem.LAUNCH_FILE, PathItem.CFG_FILE, PathItem.PROFILE, PathItem.FILE, PathItem.RECENT_FILE, PathItem.LAUNCH_FILE ]: if not has_shift_mod: return path root = self.invisibleRootItem() while root.rowCount(): root.removeRow(0) self.pyqt_workaround.clear() if has_shift_mod: if path_id in [ PathItem.LAUNCH_FILE, PathItem.CFG_FILE, PathItem.PROFILE, PathItem.FILE, PathItem.RECENT_FILE, PathItem.LAUNCH_FILE ]: self._current_path = os.path.dirname(path) else: self._current_path = nmdurl.nmduri() else: if path_id in [PathItem.ROOT]: surl, spath = nmdurl.split(path, with_scheme=True) if self._is_root(path) or spath in ['', os.path.sep]: self._current_path = nmdurl.nmduri() elif self._is_ros_root(path): self._current_path = surl else: dir_path = os.path.dirname(spath) self._current_path = nmdurl.join(surl, dir_path) elif self._current_path != path: self._current_path = path self._add_path(self._current_path, PathItem.ROOT, 0, 0, 'loading...') nm.nmd().file.list_path_threaded(self._current_path, clear_cache) # TODO: add functionality to go deep automatically # else: # key_mod = QApplication.keyboardModifiers() # onestep = False # if key_mod & Qt.ControlModifier: # onestep = True # root_path, items = self._moveDown(path, onestep) # self._setNewList((root_path, items)) return None
def get_packages(self, url=''): if url: grpc_url = nmdurl.nmduri(url) if grpc_url in self._cache_packages: return self._cache_packages[grpc_url] return {} return self._cache_packages
def __init__(self, parent=None, progress_queue=None, viewobj=None): ''' Creates a new list model. ''' QStandardItemModel.__init__(self, parent) self.viewobj = viewobj self.setColumnCount(len(LaunchListModel.header)) self.setHorizontalHeaderLabels( [label for label, _width in LaunchListModel.header]) self.pyqt_workaround = dict( ) # workaround for using with PyQt: store the python object to keep the defined attributes in the TopicItem subclass self.items = [] self._roots = {} self._current_path = nmdurl.nmduri() self._current_master = masteruri_from_master() self._current_master_name = '' self.ros_root_paths = {} # {url: [root pasth(str)]} self.ros_root_paths[self._current_path] = [ os.path.normpath(p) for p in os.getenv("ROS_PACKAGE_PATH").split(':') ] self._progress_queue = progress_queue nm.nmd().file.listed_path.connect(self._listed_path) nm.nmd().file.packages_available.connect(self._on_new_packages) nm.nmd().file.error.connect(self._nmd_error)
def get_profile_file(self): ''' Opens file manager dialog to save to select a new file for node manager profile. :return: path to profile file :rtype: str ''' # save the profile (path, _) = QFileDialog.getSaveFileName( self, "New profile file", nm.settings().current_dialog_path, "node manager profile files (*.nmprofile);;All files (*)" ) # _:=filter if path: if not path.endswith('.nmprofile'): path = "%s.nmprofile" % path nm.settings().current_dialog_path = os.path.dirname(path) try: # we need a grpc url for local node manager daemon nmd_url = nmdurl.nmduri() (pkg, _) = package_name( nmdurl.join(nmd_url, os.path.dirname(path))) # _:=pkg_path if pkg is None: ret = MessageBox.warning( self, "New File Error", 'The new file is not in a ROS package', buttons=MessageBox.Ok | MessageBox.Cancel) if ret == MessageBox.Cancel: return None return path except EnvironmentError as e: MessageBox.warning(self, "New File Error", 'Error while create a new file', utf8(e)) return None
def _add_history(self): for hitem in nm.settings().launch_history: if not hitem.startswith(os.path.sep): hitem_uri, _ = nmdurl.split(hitem, with_scheme=True) current_uri = nmdurl.nmduri(self._current_path) if nmdurl.equal_uri(hitem_uri, current_uri): self._add_path(hitem, PathItem.RECENT_FILE, 0, 0, os.path.basename(hitem))
def set_current_master(self, masteruri, mastername): self._current_master = masteruri.rstrip(os.path.sep) self._current_master_name = mastername if self._is_root(self._current_path): nm.nmd().file.list_path_threaded(self._current_path) if nmdurl.equal_uri(self._current_path, masteruri_from_master()): self._add_path(nmdurl.nmduri(self._current_master), PathItem.REMOTE_DAEMON, 0, 0, get_hostname(self._current_master_name))
def clear_package_cache(self, url): if url: grpc_url = nmdurl.nmduri(url) try: del self._cache_packages[grpc_url] rospy.logdebug("cache for packages from '%s' removed", grpc_url) except KeyError: pass
def run(self): ''' ''' if self._grpc_url: try: self._result = nm.nmd().file.get_package_binaries( self._package, nmdurl.nmduri(self._grpc_url)) if not self._canceled: self.binaries_signal.emit(self._package, self._result) except Exception: import traceback print(traceback.format_exc())
def _listed_path(self, url, path, result): if not self.is_current_nmd(url): return root = self.invisibleRootItem() while root.rowCount(): root.removeRow(0) self.pyqt_workaround.clear() # test for ROS root paths and add these if it is in ROS_PACKAGE_PATH isroot = path in ['', os.path.sep] if isroot: self.ros_root_paths[url] = [] # append path items to the list model result_list = [] for path_item in result: if isroot and path_item.type in [FileItem.DIR, FileItem.PACKAGE]: self.ros_root_paths[url].append(path_item.path) item = os.path.normpath(os.path.join(path, path_item.path)) gpath = nmdurl.join(url, item) path_id = PathItem.NOT_FOUND if FileItem.FILE == path_item.type: _, ext = os.path.splitext(path_item.path) if ext in nm.settings( ).launch_view_file_ext or path_item.path.find('.launch.') > 0: path_id = PathItem.FILE elif FileItem.DIR == path_item.type: path_id = PathItem.FOLDER elif FileItem.SYMLINK == path_item.type: pass elif FileItem.PACKAGE == path_item.type: path_id = PathItem.PACKAGE if path_id != PathItem.NOT_FOUND and not os.path.basename( path_item.path).startswith('.'): # TODO: create filter for files result_list.append( (gpath, path_id, path_item.mtime, path_item.size, os.path.basename(path_item.path))) root_path = nmdurl.join(url, path) self._set_new_list(root_path, result_list) isroot = self._is_root(self._current_path) if isroot and not nmdurl.equal_uri(self._current_master, masteruri_from_master()): self._add_path(nmdurl.nmduri(self._current_master), PathItem.REMOTE_DAEMON, 0, 0, get_hostname(self._current_master_name)) self.pathlist_handled.emit(root_path)
def on_package_selected(self, package): getnew = False if self._request_bin_thread is None: getnew = True else: if self._request_bin_thread.pkgname != package: self._request_bin_thread.cancel() getnew = True if self._request_bin_thread is not None and self._request_bin_thread.pkgname == package: # use already got data self._request_bin_thread.reemit() elif getnew: self.binary_field.clear() if self.packages and package in self.packages: self.binary_field.setEnabled(True) self._request_bin_thread = RequestBinariesThread( package, nmdurl.nmduri(self.masteruri)) self._request_bin_thread.binaries_signal.connect( self._on_new_binaries) self._request_bin_thread.start()
def _is_root(self, grpc_path): return grpc_path == nmdurl.nmduri()
def runNodeWithoutConfig(cls, host, package, binary, name, args=[], masteruri=None, use_nmd=True, auto_pw_request=False, user=None, pw=None, path=''): ''' Start a node with using a launch configuration. :param str hosturi: the host or ip to run the node :param str package: the ROS package containing the binary :param str binary: the binary of the node to execute :param str name: the ROS name of the node (with name space) :param args: the list with arguments passed to the binary :type args: [str] :param bool use_nmd: start the node using node manager daemon :param bool auto_pw_request: opens question dialog directly, use True only if the method is called from the main GUI thread :raise Exception: on errors while resolving host :see: :meth:`fkie_node_manager.is_local()` ''' # create the name with namespace args2 = list(args) fullname = roslib.names.ns_join(roslib.names.SEP, name) namespace = '' for a in args: if a.startswith('__ns:='): namespace = a.replace('__ns:=', '') fullname = roslib.names.ns_join(namespace, name) args2.append(''.join(['__name:=', name])) # run on local host if nm.is_local(host, wait=True): if not use_nmd: if path: cmd = [path] else: try: cmd = roslib.packages.find_node(package, binary) except roslib.packages.ROSPkgException as e: # multiple nodes, invalid package raise StartException(utf8(e)) # handle different result types str or array of string if isstring(cmd): cmd = [cmd] cmd_type = '' if cmd is None or len(cmd) == 0: raise StartException('%s in package [%s] not found!' % (binary, package)) # compatibility for python scripts installed with catkin_install_python() # avoid ask for select a binary cmd = cls._remove_src_binary(cmd) if len(cmd) > 1: # Open selection for executables err = 'Multiple executables with same name in package [%s] found' % package bsel = nm.BinarySelectionRequest(cmd, err) raise nm.InteractionNeededError( bsel, cls.runNodeWithoutConfig, { 'host': host, 'package': package, 'binary': binary, 'name': name, 'args': args, 'masteruri': masteruri, 'use_nmd': use_nmd, 'auto_pw_request': auto_pw_request, 'user': user, 'pw': pw, 'path': path }) else: cmd_type = cmd[0] new_env = {} # dict(os.environ) if namespace: new_env['ROS_NAMESPACE'] = namespace if masteruri is not None: cls._prepareROSMaster(masteruri) new_env['ROS_MASTER_URI'] = masteruri if 'ROS_HOSTNAME' in os.environ: # set ROS_HOSTNAME only if node_manager has also one ros_hostname = nmdhost.get_ros_hostname(masteruri, host) if ros_hostname: new_env['ROS_HOSTNAME'] = ros_hostname if use_nmd: nm.nmd().launch.start_standalone_node(nmdurl.nmduri(), package, binary, name, namespace, args, new_env, masteruri, host) else: local_env = dict(os.environ) local_env.update(new_env) cmd_str = utf8(' '.join([ screen.get_cmd(fullname, local_env), cmd_type, ' '.join(args2) ])) rospy.loginfo("Run without config: %s", fullname if use_nmd else cmd_str) SupervisedPopen(shlex.split(cmd_str), env=local_env, object_id="Run without config", description="Run without config [%s]%s" % (utf8(package), utf8(binary))) else: # run on a remote machine startcmd = [ nm.settings().start_remote_script, '--package', utf8(package), '--node_type', utf8(binary), '--node_name', utf8(fullname) ] startcmd[len(startcmd):] = args2 if masteruri is not None: startcmd.append('--masteruri') startcmd.append(masteruri) rospy.loginfo("Run remote on %s: %s", host, ' '.join(startcmd)) try: _, stdout, stderr, ok = nm.ssh().ssh_exec(host, startcmd, user, pw, auto_pw_request, close_stdin=True) if ok: output = stdout.read() error = stderr.read() stdout.close() stderr.close() if error: rospy.logwarn("ERROR while start '%s': %s", name, error) raise StartException(''.join( ['The host "', host, '" reports:\n', error])) if output: if output.find("dn't") != -1: rospy.logwarn("Warning while start '%s': %s", name, output) else: rospy.loginfo("STDOUT while start '%s': %s", name, output) else: if error: rospy.logwarn("ERROR while start '%s': %s", name, error) raise StartException(''.join( ['The host "', host, '" reports:\n', error])) except nm.AuthenticationRequest as e: raise nm.InteractionNeededError( e, cls.runNodeWithoutConfig, { 'host': host, 'package': package, 'binary': binary, 'name': name, 'args': args, 'masteruri': masteruri, 'use_nmd': use_nmd, 'auto_pw_request': auto_pw_request, 'user': user, 'pw': pw, 'path': path })
def __init__(self, masteruri, parent=None): QDialog.__init__(self, parent) self.setWindowTitle('Select Binary') self.verticalLayout = QVBoxLayout(self) self.verticalLayout.setObjectName("verticalLayout") self.content = QWidget() self.contentLayout = QFormLayout(self.content) self.contentLayout.setVerticalSpacing(0) self.verticalLayout.addWidget(self.content) self.packages = None self.masteruri = "ROS_MASTER_URI" if masteruri is None else masteruri package_label = QLabel("Package:", self.content) self.package_field = QComboBox(self.content) self.package_field.setInsertPolicy(QComboBox.InsertAlphabetically) self.package_field.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)) self.package_field.setEditable(True) self.contentLayout.addRow(package_label, self.package_field) binary_label = QLabel("Binary:", self.content) self.binary_field = QComboBox(self.content) self.binary_field.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)) self.binary_field.setEditable(True) self.contentLayout.addRow(binary_label, self.binary_field) self.buttonBox = QDialogButtonBox(self) self.buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setObjectName("buttonBox") self.verticalLayout.addWidget(self.buttonBox) self.package_field.setFocus(Qt.TabFocusReason) self.package = '' self.binary = '' self._request_bin_thread = None if self.packages is None: self.package_field.addItems(['packages searching...']) self.package_field.setCurrentIndex(0) # fill the input fields self.packages = { name: path for path, name in nm.nmd().file.get_packages( nmdurl.nmduri(masteruri)).items() } packages = self.packages.keys() packages.sort() self.package_field.clear() self.package_field.clearEditText() self.package_field.addItems(packages) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) QMetaObject.connectSlotsByName(self) self.package_field.activated[str].connect(self.on_package_selected) if hasattr(self.package_field, "textChanged"): # qt compatibility self.package_field.textChanged.connect(self.on_package_selected) self.binary_field.textChanged.connect(self.on_binary_selected) else: self.package_field.editTextChanged.connect( self.on_package_selected) self.binary_field.editTextChanged.connect(self.on_binary_selected)
def on_load_profile_file(self, grpc_url): ''' Load the profile file. :param str grpc_url: the path of the profile file. ''' _url, path = nmdurl.split(grpc_url) rospy.loginfo("Load profile %s" % path) self.progressBar.setValue(0) self.setVisible(True) self.setWindowTitle("%s profile started" % os.path.basename(path).rstrip('.nmprofile')) hasstart = False if path: try: with open(path, 'r') as f: content = ruamel.yaml.load(f.read(), Loader=ruamel.yaml.Loader) if not isinstance(content, dict): raise Exception("Mailformed profile: %s" % os.path.basename(path)) for muri, master_dict in content.items(): local_hostname = get_hostname( self._main_window.getMasteruri()) rmuri = muri.replace('$LOCAL$', local_hostname) master = self._main_window.getMaster(rmuri) running_nodes = master.get_nodes_runningIfLocal() usr = None self._current_profile[rmuri] = set() if 'user' in master_dict: usr = master_dict['user'] if master_dict['mastername'] and master_dict[ 'mastername']: nm.nameres().add_master_entry( master.masteruri, master_dict['mastername'], master_dict['address']) hostname = master_dict['address'].replace( '$LOCAL$', local_hostname) if 'master_discovery' in master_dict: self._start_node_from_profile( master, hostname, 'fkie_master_discovery', 'master_discovery', usr, cfg=master_dict['master_discovery']) self._current_profile[rmuri].add( '/master_discovery') if 'master_sync' in master_dict: self._start_node_from_profile( master, hostname, 'fkie_master_sync', 'master_sync', usr, cfg=master_dict['master_sync']) self._current_profile[rmuri].add('/master_sync') if 'zeroconf' in master_dict: self._start_node_from_profile( master, hostname, 'fkie_master_discovery', 'zeroconf', usr, cfg=master_dict['zeroconf']) self._current_profile[rmuri].add('/zeroconf') if 'node_manager_daemon' in master_dict: self._start_node_from_profile( master, hostname, 'fkie_node_manager_daemon', 'node_manager_daemon', usr, cfg=master_dict['node_manager_daemon']) self._current_profile[rmuri].add( '/node_manager_daemon') try: do_start = [] do_not_stop = { '/rosout', rospy.get_name(), '/node_manager', '/master_discovery', '/master_sync', '*default_cfg', '/zeroconf', '/node_manager_daemon' } configs = master_dict['configs'] conf_set = set() for cfg_name, cmdict in configs.items(): cfg_name = cfg_name.replace( '$LOCAL$', local_hostname) if cfg_name.startswith("pkg://"): cfg_name = resolve_pkg( cfg_name, nmdurl.nmduri(rmuri)) conf_set.add(cfg_name) reload_launch = True args = {} if 'args' in cmdict: if 'args' in cmdict: args = cmdict['args'] # do we need to load to load/reload launch file if cfg_name in master.launchfiles: reload_launch = set( master.launchfiles[cfg_name].args. itervalues()) != set( args.itervalues()) if reload_launch: self._main_window.launch_dock.load_file( cfg_name, args, master.masteruri) if 'nodes' in cmdict: self._current_profile[rmuri].update( cmdict['nodes']) force_start = True cfg = cfg_name if not reload_launch: force_start = False do_not_stop.update(set( cmdict['nodes'])) do_start.append( (reload_launch, cfg, cmdict['nodes'], force_start)) else: do_start.append( (reload_launch, cfg, cmdict['nodes'], force_start)) # close unused configurations for lfile in set( master.launchfiles.keys()) - conf_set: master._close_cfg(lfile) master.stop_nodes_by_name(running_nodes.keys(), True, do_not_stop) for reload_launch, cfg, nodes, force_start in do_start: if nodes: hasstart = True if reload_launch: master.start_nodes_after_load_cfg( cfg, list(nodes), force_start) else: master.start_nodes_by_name( list(nodes), cfg, force_start) except Exception as ml: import traceback print(utf8(traceback.format_exc(1))) rospy.logwarn( "Can not load launch file for %s: %s" % (muri, utf8(ml))) except Exception as e: import traceback print(traceback.format_exc(1)) MessageBox.warning(self, "Load profile error", 'Error while load profile', utf8(e)) if not hasstart: self.update_progress() else: QTimer.singleShot(1000, self.update_progress)