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
35 """
36 Rules for checking ROS environment state.
37 """
38
39 import os
40 import socket
41 import stat
42 import string
43 import sys
44
45 from os.path import isdir, isfile
46 from roswtf.rules import warning_rule, error_rule
47
48
49
51 """
52 @return: paths contained in path variable. path must conform to OS
53 conventions for path separation (i.e. colon-separated on Unix)
54 @rtype: [str]
55 """
56 if path:
57 return path.split(os.pathsep)
58 return []
59
61 """
62 @return: True if path has executable permissions
63 @rtype: bool
64 """
65 mode = os.stat(path)[stat.ST_MODE]
66 return mode & (stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH)
67
68 try:
69 from urllib.parse import urlparse
70 except ImportError:
71 from urlparse import urlparse
72
74 """
75 @return: error message if \a url is not a valid url. \a url is
76 allowed to be empty as that check is considered separately.
77 @rtype: str
78 """
79 if not url:
80 return
81 p = urlparse(url)
82 if p[0] != 'http':
83 return "protocol is not 'http'"
84 if not p[1]:
85 return "address is missing"
86 if not ':' in p[1]:
87 return "port number is missing"
88 try:
89 splits = p[1].split(':')
90 if len(splits) != 2:
91 return "invalid address string [%s]"%p[1]
92 int(splits[1])
93 except ValueError:
94 return "port number [%s] is invalid"%(splits[1])
95
96
97
99 """
100 @param ros_root: override ctx, useful for when ctx is not created yet
101 @type ros_root: str
102 """
103 if ros_root is not None:
104 path = ros_root
105 else:
106 path = ctx.ros_root
107 if os.path.basename(os.path.normpath(path)) not in ['ros', 'rosbuild']:
108 return "ROS_ROOT [%s] must end in directory named 'ros'"%path
109
111 """
112 If path is not None, validate that it is a writable directory
113 """
114 if path is None:
115 return
116 if isfile(path):
117 return "%s [%s] must point to a directory, not a file"%(name, path)
118 if not os.access(path, os.W_OK):
119 return "%s [%s] is not writable"%(name, path)
120
122 return _writable_dir_check(ctx, ctx.env.get('ROS_HOME', None), 'ROS_HOME')
124 return _writable_dir_check(ctx, ctx.env.get('ROS_LOG_DIR', None), 'ROS_LOG_DIR')
126 return _writable_dir_check(ctx, ctx.env.get('ROS_TEST_RESULTS_DIR', None), 'ROS_TEST_RESULTS_DIR')
127
129
130 path = ctx.pythonpath
131 roslib_count = len(set([p for p in paths(path) if 'roslib' in p]))
132 if roslib_count > 1:
133 return "Multiple roslib directories in PYTHONPATH (there should only be one)"
134
136 if 'ROSCONSOLE_CONFIG_FILE' in ctx.env:
137 return not isfile(ctx.env['ROSCONSOLE_CONFIG_FILE'])
138
140
141 path = ctx.env['PATH']
142 idx = path.find('/usr/bin')
143 if idx < 0:
144 return
145 if os.path.exists('/usr/lib/ros/'):
146 rr_idx = path.find(ctx.ros_root)
147 if rr_idx > -1 and rr_idx > idx:
148 return True
149
151 uri = ctx.ros_master_uri
152 parsed = urlparse(uri)
153 p = urlparse(uri)
154 if not p[1]:
155 return
156 if not ':' in p[1]:
157 return
158 try:
159 splits = p[1].split(':')
160 if len(splits) != 2:
161 return
162
163 socket.getaddrinfo(splits[0], 0, 0, 0, socket.SOL_TCP)
164
165 except socket.gaierror:
166 return "Unknown host %s"%splits[0]
167
168
169
170 environment_warnings = [
171 (path_check,
172 "PATH has /usr/bin set before ROS_ROOT/bin, which can cause problems as there is system install of ROS on this machine. You may wish to put ROS_ROOT/bin first"),
173 (lambda ctx: ctx.ros_package_path is None,
174 "ROS_PACKAGE_PATH is not set. This is not required, but is unusual"),
175 (lambda ctx: len(paths(ctx.ros_package_path)) == 0,
176 "ROS_PACKAGE_PATH is empty. This is not required, but is unusual"),
177 (lambda ctx: not ctx.ros_master_uri,
178 "ROS_MASTER_URI is empty. This is not required, but is unusual"),
179 (ros_master_uri_hostname,
180 "Cannot resolve hostname in ROS_MASTER_URI [%(ros_master_uri)s]"),
181 (rosconsole_config_file_check,
182 "ROS_CONSOLE_CONFIG_FILE does not point to an existing file"),
183 ]
184
185 environment_errors = [
186
187 (lambda ctx: not isdir(ctx.ros_root),
188 "ROS_ROOT [%(ros_root)s] does not point to a directory"),
189 (ros_root_check,
190 "ROS_ROOT is invalid: "),
191
192
193 (lambda ctx: [d for d in paths(ctx.ros_package_path) if d and isfile(d)],
194 "Path(s) in ROS_PACKAGE_PATH [%(ros_package_path)s] points to a file instead of a directory: "),
195 (lambda ctx: [d for d in paths(ctx.ros_package_path) if d and not isdir(d) and not (os.path.basename(d) == 'stacks' and os.path.exists(os.path.join(os.path.dirname(d), '.catkin')))],
196 "Not all paths in ROS_PACKAGE_PATH [%(ros_package_path)s] point to an existing directory: "),
197
198
199 (lambda ctx: [d for d in paths(ctx.pythonpath) if d and not isdir(d)],
200 "Not all paths in PYTHONPATH [%(pythonpath)s] point to a directory: "),
201 (pythonpath_check,
202 "PYTHONPATH [%(pythonpath)s] is invalid: "),
203
204
205 (ros_home_check, "ROS_HOME is invalid: "),
206 (ros_log_dir_check, "ROS_LOG_DIR is invalid: "),
207 (ros_test_results_dir_check, "ROS_TEST_RESULTS_DIR is invalid: "),
208
209 (lambda ctx: invalid_url(ctx.ros_master_uri),
210 "ROS_MASTER_URI [%(ros_master_uri)s] is not a valid URL: "),
211
212 ]
213
220