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 import os
37 import subprocess
38 import tempfile
39
40 if __name__ == '__main__':
41 import roslib; roslib.load_manifest('rosdeb')
42
43 import roslib.manifest
44 import roslib.stack_manifest
45 import roslib.packages
46 import vcstools
47
48 import rosdeb
49
50
51 roslib.load_manifest('rosdep')
52 import rosdep
53 from rosdep.core import RosdepLookupPackage, YamlCache
54
55 IMPLICIT_DEPS = ['libc6','build-essential','cmake','python-yaml','subversion']
56
57 -def _text_only(soup):
58 return ''.join(soup.findAll(text=True))
59
61 """
62 Checkout an SVN tree to the tmp dir.
63
64 Utility routine -- need to replace with vcs
65
66 @return: temporary directory that contains checkout of SVN tree in
67 directory 'name'. temporary directory will be a subdirectory of
68 OS-provided temporary space.
69 @rtype: str
70 """
71 tmp_dir = tempfile.mkdtemp()
72 dest = os.path.join(tmp_dir, name)
73 print 'Checking out a fresh copy of %s from %s to %s...'%(name, uri, dest)
74 subprocess.check_call(['svn', 'co', uri, dest])
75 return tmp_dir
76
78 """
79 Checkout an VCS-based 'dev' code tree to the tmp dir.
80
81 @return: temporary directory that contains checkout of SVN tree in
82 directory 'name'. temporary directory will be a subdirectory of
83 OS-provided temporary space.
84 @rtype: str
85 """
86 for key in ['svn', 'git', 'hg', 'bzr']:
87 if key in distro_stack._rules:
88 break
89 else:
90 raise Exception("stack [%s] does not have any supported checkout rules"%(name))
91
92 try:
93 if key == 'svn':
94 uri = distro_stack.expand_rule(distro_stack._rules[key]['dev'])
95 version = ''
96 elif key in ['hg', 'git', 'bzr']:
97 uri = distro_stack.expand_rule(distro_stack._rules[key]['uri'])
98 version = distro_stack.expand_rule(distro_stack._rules[key]['dev-branch'])
99 else:
100 raise Exception ("key %s not implemented"%key)
101
102 except KeyError:
103 raise Exception("cannot checkout stack dev tree to tmp: %s rules have no 'dev' key"%(key))
104
105 tmp_dir = tempfile.mkdtemp()
106 dest = os.path.join(tmp_dir, name)
107 print 'Checking out a fresh copy of %s from %s to %s...'%(name, uri, dest)
108 vcs_client = vcstools.VcsClient(key, dest)
109 vcs_client.checkout(uri, version)
110 return tmp_dir
111
113 """
114 Convert a HTML description to plain text. This routine still has
115 much work to do, but appears to handle the common uses of HTML in
116 our current manifests.
117 """
118
119 if '<' in d:
120 from rosdeb.BeautifulSoup import BeautifulSoup
121 soup = BeautifulSoup(d)
122
123
124 for t in ['b', 'strong', 'em', 'i', 'tt', 'a']:
125 tags = soup.findAll(t)
126 for x in tags:
127 x.replaceWith(_text_only(x))
128
129
130 tags = soup.findAll('li')
131 for x in tags:
132 x.replaceWith('* '+_text_only(x)+'\n')
133
134
135 for t in ['p', 'div']:
136 tags = soup.findAll(t)
137 for t in tags:
138 t.replaceWith(_text_only(t)+'\n')
139
140
141 d = ''.join(soup.findAll(text=True))
142
143
144
145
146 d = '\n'.join([x.strip() for x in d.split('\n')])
147
148 d_reduced = ''
149 last = None
150 for x in d.split('\n'):
151 if last is None:
152 d_reduced = x
153 else:
154 if x == '':
155 if last == '':
156 pass
157 else:
158 d_reduced += '\n'
159 else:
160 d_reduced += x + ' '
161 last = x
162 return d_reduced
163
164
166 """
167 @return: list of package names and manifest file paths for stack
168 dir. These will be returned as a list of (name, path) pairs.
169 @rtype: [(str, str)]
170 """
171
172 m_file = os.path.join(stack_dir, 'manifest.xml')
173 if os.path.isfile(m_file):
174 return [(os.path.basename(os.path.abspath(stack_dir)), m_file),]
175
176 l = [os.path.join(stack_dir, d) for d in os.listdir(stack_dir)]
177 manifests = []
178 packages = []
179 while l:
180 d = l.pop()
181 if os.path.isdir(d):
182 if roslib.packages.is_pkg_dir(d):
183 p = os.path.basename(d)
184 m_file = os.path.join(d, 'manifest.xml')
185
186 if not p in packages:
187 packages.append(p)
188 manifests.append((p, m_file))
189 elif os.path.exists(os.path.join(d, 'rospack_nosubdirs')):
190
191 pass
192 elif os.path.basename(d) not in ['build', '.svn', '.git']:
193 l.extend([os.path.join(d, e) for e in os.listdir(d)])
194 return manifests
195
197 """
198 Calculate dependencies of stack on an 'ubuntu' OS, including both
199 ROS stacks and their rosdep dependencies, for the specified
200 ubuntu release version.
201
202 NOTE: one flaw in this implementation is that it uses the rosdep
203 view from the *active environment* to generate the rosdeps. It
204 does not generate them from specific versions of stacks. The hope
205 is that rosdeps improve monotonically over time, so that this will
206 not be a major issue.
207
208 @param platform: platform name (e.g. lucid)
209
210 @return: list of debian package deps
211 @rtype: [str]
212 @raise Exception: if stack rosdeps cannot be fully resolved
213 """
214
215
216 deb_deps = IMPLICIT_DEPS[:]
217
218
219 os_name = 'ubuntu'
220
221 os_version = [k for k, v in rosdeb.get_ubuntu_map().iteritems() if v == platform][0]
222
223 try:
224
225 import rosdep.installers
226 installers = {'apt': rosdep.installers.AptInstaller, 'source': rosdep.installers.SourceInstaller}
227 os_version = platform
228 yc = YamlCache(os_name, os_version, installers)
229
230 except ImportError:
231 yc = YamlCache(os_name, os_version)
232
233 package_manifests = package_manifests_of(stack_dir)
234 for p, m_file in package_manifests:
235 m = roslib.manifest.parse_file(m_file)
236 rosdeps = [d.name for d in m.rosdeps]
237 if not rosdeps:
238 continue
239
240 rdlp = RosdepLookupPackage(os_name, os_version, p, yc)
241 for r in rosdeps:
242 value = rdlp.lookup_rosdep(r)
243 if value is False:
244 raise Exception("cannot generate rosdeps for stack [%s] on platform [%s]:\n\trosdep lookup of [%s] failed"%(stack_name, os_version, r))
245 if type(value) == dict:
246 if 'apt' in value:
247 packages = value['apt']['packages']
248 if type(packages) == list:
249 deb_deps.extend(packages)
250 else:
251 deb_deps.append(packages)
252 else:
253 if '\n' in value:
254 raise Exception("cannot generate rosdeps for stack [%s] on platform [%s]:\n\trosdep [%s] has a script binding"%(stack_name, os_version, r))
255
256 deb_deps.extend([x for x in value.split(' ') if x.strip()])
257
258 return list(set(deb_deps))
259
261 """
262 Calculate list of rosdeps that are missing definitions on platform.
263
264 NOTE: one flaw in this implementation is that it uses the rosdep
265 view from the *active environment* to generate the rosdeps. It
266 does not generate them from specific versions of stacks. The hope
267 is that rosdeps improve monotonically over time, so that this will
268 not be a major issue.
269
270 @param platform: platform name (e.g. lucid)
271 @return: dictionary mapping packages to their missing rosdep mappings
272 @rtype: {str: [str]}
273 """
274
275
276 os_name = 'ubuntu'
277
278 os_version = [k for k, v in rosdeb.get_ubuntu_map().iteritems() if v == platform][0]
279
280 yc = YamlCache(os_name, os_version)
281 package_manifests = package_manifests_of(stack_dir)
282 packages = {}
283 for p, m_file in package_manifests:
284 missing = []
285 packages[p] = missing
286 m = roslib.manifest.parse_file(m_file)
287 rosdeps = [d.name for d in m.rosdeps]
288 if not rosdeps:
289 continue
290
291 rdlp = RosdepLookupPackage(os_name, os_version, p, yc)
292 for r in rosdeps:
293 value = rdlp.lookup_rosdep(r)
294 if not value or '\n' in value:
295 missing.append(r)
296 return packages
297
298 -def send_email(smtp_server, from_addr, to_addrs, subject, text):
299 import smtplib
300 from email.mime.text import MIMEText
301
302 msg = MIMEText(text)
303
304 msg['From'] = from_addr
305 msg['To'] = to_addrs
306 msg['Subject'] = subject
307
308 s = smtplib.SMTP(smtp_server)
309 print 'Sending mail to %s'%(to_addrs)
310 try:
311 s.sendmail(msg['From'], [msg['To']], msg.as_string())
312 except Exception, ex:
313 print "Sending email failed with exception: %s" % ex
314 s.quit()
315
316 if __name__ == '__main__':
317 import roslib.stacks
318 from rosdeb.rosutil import convert_html_to_text
319 from roslib.stack_manifest import parse_file, stack_file
320 for stack_name in roslib.stacks.list_stacks():
321 stack_xml = stack_file(stack_name)
322 m = roslib.stack_manifest.parse_file(stack_xml)
323 if stack_name in ['ros_release']:
324 print '='*80
325 print stack_name
326 print convert_html_to_text(m.description)
327