Package node_manager_fkie
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 import argparse
35 import os
36 import roslib.network
37 import rospy
38 import socket
39 import subprocess
40 import sys
41 import threading
42
43 from master_discovery_fkie.common import get_hostname
44 from node_manager_fkie.common import get_ros_home, masteruri_from_ros
45 from node_manager_fkie.file_watcher import FileWatcher
46 from node_manager_fkie.history import History
47 from node_manager_fkie.master_view_proxy import LaunchArgsSelectionRequest
48 from node_manager_fkie.name_resolution import NameResolution
49 from node_manager_fkie.progress_queue import InteractionNeededError
50 from node_manager_fkie.screen_handler import ScreenHandler, ScreenSelectionRequest, NoScreenOpenLogRequest
51 from node_manager_fkie.settings import Settings
52 from node_manager_fkie.ssh_handler import SSHhandler, AuthenticationRequest
53 from node_manager_fkie.start_handler import StartException, AdvRunCfg
54 from node_manager_fkie.start_handler import StartHandler, BinarySelectionRequest
55
56
57 PKG_NAME = 'node_manager_fkie'
58
59 __author__ = "Alexander Tiderko (Alexander.Tiderko@fkie.fraunhofer.de)"
60 __copyright__ = "Copyright (c) 2012 Alexander Tiderko, Fraunhofer FKIE/US"
61 __license__ = "BSD"
62 __version__ = "unknown"
63 __date__ = "unknown"
64
65
66
67
68
69
70 HOSTS_CACHE = dict()
71 '''
72 the cache directory to store the results of tests for local hosts.
73 @see: L{is_local()}
74 '''
75
76 _LOCK = threading.RLock()
77
78 _MAIN_FORM = None
79 _SETTINGS = None
80 _SSH_HANDLER = None
81 _SCREEN_HANDLER = None
82 _START_HANDLER = None
83 _NAME_RESOLUTION = None
84 _HISTORY = None
85 _FILE_WATCHER = None
86 _FILE_WATCHER_PARAM = None
87 _QAPP = None
88
89
91 '''
92 @return: The global settings
93 @rtype: L{Settings}
94 '''
95 return _SETTINGS
96
97
99 '''
100 @return: The SSH handler to handle the SSH connections
101 @rtype: L{SSHhandler}
102 '''
103 return _SSH_HANDLER
104
105
107 '''
108 @return: The screen handler to the screens.
109 @rtype: L{ScreenHandler}
110 @see: U{http://linuxwiki.de/screen}
111 '''
112 return _SCREEN_HANDLER
113
114
116 '''
117 @return: The start handler to handle the start of new ROS nodes on local or
118 remote machines.
119 @rtype: L{StartHandler}
120 '''
121 return _START_HANDLER
122
123
125 '''
126 @return: The name resolution object translate the the name to the host or
127 ROS master URI.
128 @rtype: L{NameResolution}
129 '''
130 return _NAME_RESOLUTION
131
132
134 '''
135 @return: The history of entered parameter.
136 @rtype: L{History}
137 '''
138 return _HISTORY
139
140
142 '''
143 @return: The file watcher object with all loaded configuration files.
144 @rtype: L{FileWatcher}
145 '''
146 return _FILE_WATCHER
147
148
150 '''
151 @return: The file watcher object with all configuration files referenced by
152 parameter value.
153 @rtype: L{FileWatcher}
154 '''
155 return _FILE_WATCHER_PARAM
156
157
159 '''
160 Returns the host name used in a url, if it is a name. If it is an IP an
161 empty string will be returned.
162
163 @return: host or '' if url is an IP or invalid
164
165 @rtype: C{str}
166 '''
167 return NameResolution.get_ros_hostname(url)
168
169
171 '''
172 Test whether the given host name is the name of the local host or not.
173 @param hostname: the name or IP of the host
174 @type hostname: C{str}
175 @return: C{True} if the hostname is local or None
176 @rtype: C{bool}
177 @raise Exception: on errors while resolving host
178 '''
179 if hostname is None:
180 return True
181 with _LOCK:
182 if hostname in HOSTS_CACHE:
183 if isinstance(HOSTS_CACHE[hostname], threading.Thread):
184 return False
185 return HOSTS_CACHE[hostname]
186 try:
187 socket.inet_aton(hostname)
188 local_addresses = ['localhost'] + roslib.network.get_local_addresses()
189
190 result = hostname.startswith('127.') or hostname in local_addresses
191 with _LOCK:
192 HOSTS_CACHE[hostname] = result
193 return result
194 except socket.error:
195
196 if wait:
197 result = __is_local(hostname)
198 return result
199 else:
200 thread = threading.Thread(target=__is_local, args=((hostname,)))
201 thread.daemon = True
202 with _LOCK:
203 HOSTS_CACHE[hostname] = thread
204 thread.start()
205 return False
206
207
209 '''
210 Test the hostname whether it is local or not. Uses socket.gethostbyname().
211 '''
212 try:
213 machine_addr = socket.gethostbyname(hostname)
214 except socket.gaierror:
215 with _LOCK:
216 HOSTS_CACHE[hostname] = False
217 return False
218 local_addresses = ['localhost'] + roslib.network.get_local_addresses()
219
220 result = machine_addr.startswith('127.') or machine_addr in local_addresses
221 with _LOCK:
222 HOSTS_CACHE[hostname] = result
223 return result
224
225
227 '''
228 Try to detect the current version from git, installed VERSION/DATE files or package.xml
229 '''
230 try:
231 global __version__
232 global __date__
233 pkg_path = roslib.packages.get_pkg_dir(PKG_NAME)
234 if pkg_path is not None and os.path.isfile("%s/VERSION" % pkg_path):
235 try:
236 with open("%s/VERSION" % pkg_path) as f:
237 version = f.read()
238 __version__ = version.strip()
239 with open("%s/DATE" % pkg_path) as f:
240 datetag = f.read().split()
241 if datetag:
242 __date__ = datetag[0]
243 except Exception as err:
244 print >> sys.stderr, "version detection error: %s" % err
245 elif os.path.isdir("%s/../.git" % settings().PACKAGE_DIR):
246 try:
247 os.chdir(settings().PACKAGE_DIR)
248 ps = subprocess.Popen(args=['git', 'describe', '--tags', '--dirty', '--always'], stdin=None, stdout=subprocess.PIPE, stderr=None)
249 output = ps.stdout.read()
250 ps.wait()
251 __version__ = output.strip()
252 ps = subprocess.Popen(args=['git', 'show', '-s', '--format=%ci'], stdin=None, stdout=subprocess.PIPE, stderr=None)
253 output = ps.stdout.read().split()
254 if output:
255 __date__ = output[0]
256 ps.wait()
257 except Exception as err:
258 print >> sys.stderr, "version detection error: %s" % err
259 else:
260 import xml.dom
261 import xml.dom.minidom as dom
262 ppath = roslib.packages.find_resource(PKG_NAME, 'package.xml')
263 if ppath:
264 doc = dom.parse(ppath[0])
265 version_tags = doc.getElementsByTagName("version")
266 if version_tags:
267 version = version_tags[0].firstChild.data
268 __version__ = version
269 else:
270 print >> sys.stderr, "version detection: no version tag in package.xml found!"
271 else:
272 print >> sys.stderr, "version detection: package.xml not found!"
273 except Exception as err:
274 print >> sys.stderr, "version detection error: %s" % err
275
276
296
297
299 '''
300 Change the terminal name.
301 @param name: New name of the terminal
302 @type name: C{str}
303 '''
304 sys.stdout.write("\x1b]2;%s\x07" % name)
305
306
308 '''
309 Change the process name.
310 @param name: New process name
311 @type name: C{str}
312 '''
313 try:
314 from ctypes import cdll, byref, create_string_buffer
315 libc = cdll.LoadLibrary('libc.so.6')
316 buff = create_string_buffer(len(name) + 1)
317 buff.value = name
318 libc.prctl(15, byref(buff), 0, 0, 0)
319 except:
320 pass
321
322
326
327
352
353
355 parser = argparse.ArgumentParser()
356 parser.add_argument("--version", action="version", version="%s %s" % ("%(prog)s", __version__))
357 parser.add_argument("-f", "--file", nargs=1, help="loads the given file as default on start")
358 parser.add_argument("-m", "--muri", nargs=1, default='', help="starts ROS master with given URI, usefull on hosts "
359 "with multiple interfaces. ROS_HOSTNAME will be set "
360 "to the host of this URI, but only if it is not an IP.")
361
362 group = parser.add_argument_group('echo')
363 group.add_argument("--echo", nargs=2, help="starts an echo dialog instead of node manager", metavar=('name', 'type'))
364 group.add_argument("--hz", action="store_true", help="shows only the Hz value instead of topic content in echo dialog")
365 group.add_argument("--ssh", action="store_true", help="connects via SSH")
366
367 return parser
368
369
370 -def init_echo_dialog(prog_name, masteruri, topic_name, topic_type, hz=False, use_ssh=False):
384
385
386 -def init_main_window(prog_name, masteruri, launch_files=[]):
387 '''
388 Intialize the environment to start Node Manager.
389 '''
390
391 StartHandler._prepareROSMaster(masteruri)
392
393 try:
394 log_level = getattr(rospy, rospy.get_param('/%s/log_level' % prog_name, "INFO"))
395 except Exception as err:
396 print("Error while set the log level: %s\n->INFO level will be used!" % err)
397 log_level = rospy.INFO
398 rospy.init_node(prog_name, anonymous=False, log_level=log_level)
399 set_terminal_name(prog_name)
400 set_process_name(prog_name)
401 from node_manager_fkie.main_window import MainWindow
402 local_master = init_globals(masteruri)
403 return MainWindow(launch_files, not local_master, launch_files)
404
405
406
407
408
409
411 '''
412 Start the NodeManager or EchoDialog.
413 :param name: the name propagated to the rospy.init_node()
414 :type name: str
415 '''
416 try:
417 from python_qt_binding.QtGui import QApplication
418 except:
419 try:
420 from python_qt_binding.QtWidgets import QApplication
421 except:
422 print >> sys.stderr, "please install 'python_qt_binding' package!!"
423 sys.exit(-1)
424
425 init_settings()
426 detect_version()
427 parser = init_arg_parser()
428 args = rospy.myargv(argv=sys.argv)
429 parsed_args = parser.parse_args(args[1:])
430 if parsed_args.muri:
431 masteruri = parsed_args.muri[0]
432 hostname = NameResolution.get_ros_hostname(masteruri)
433 os.environ['ROS_MASTER_URI'] = masteruri
434 if hostname:
435 os.environ['ROS_HOSTNAME'] = hostname
436 masteruri = settings().masteruri()
437
438 global _QAPP
439 _QAPP = QApplication(sys.argv)
440
441
442 global _MAIN_FORM
443 try:
444 if parsed_args.echo:
445 _MAIN_FORM = init_echo_dialog(name, masteruri, parsed_args.echo[0],
446 parsed_args.echo[1], parsed_args.hz,
447 parsed_args.ssh)
448 else:
449 _MAIN_FORM = init_main_window(name, masteruri, parsed_args.file)
450 except Exception as err:
451 sys.exit("%s" % err)
452
453 exit_code = 0
454
455 if not rospy.is_shutdown():
456
457 os.chdir(settings().PACKAGE_DIR)
458
459 screen_size = QApplication.desktop().availableGeometry()
460 if (_MAIN_FORM.size().width() >= screen_size.width() or
461 _MAIN_FORM.size().height() >= screen_size.height() - 24):
462 _MAIN_FORM.showMaximized()
463 else:
464 _MAIN_FORM.show()
465 exit_code = -1
466 rospy.on_shutdown(finish)
467 exit_code = _QAPP.exec_()
468 return exit_code
469