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 from __future__ import with_statement
35
36 import os
37 import sys
38 import time
39 from subprocess import check_call
40 import hashlib
41
42 import yaml
43
44 import roslib.packages
45
46 from rosdeb.rosutil import convert_html_to_text, stack_rosdeps
47 from rosdeb.core import ubuntu_release, debianize_name, debianize_version, platforms, ubuntu_release_name
48
49 -def make_source_deb(distro_name, stack_name, stack_version, os_platform_name, staging_dir):
50 """
51 @param os_platform_name: Name of OS platform/version, e.g. 'lucid'
52 @type os_platform_name: str
53 @return: list of source-deb files
54 @rtype: [str]
55 """
56 debian_name = 'ros-%s-%s'%(distro_name, debianize_name(stack_name))
57
58 tmpl_d = os.path.join(roslib.packages.get_pkg_dir('rosdeb'), 'resources', 'source_deb')
59
60 tarball = os.path.join(staging_dir, "%s-%s.tar.bz2"%(stack_name, stack_version))
61 if not os.path.exists(tarball):
62 raise Exception("tarball must be copied to staging directory first")
63
64
65 files = []
66
67
68 stack_d = os.path.join(staging_dir, stack_name)
69 debian_d = os.path.join(stack_d, 'debian')
70 if not os.path.exists(debian_d):
71 os.makedirs(debian_d)
72
73
74 for f in ['rules', 'compat', 'postinst']:
75 files.append( (os.path.join(tmpl_d, f), os.path.join(debian_d, f)) )
76
77
78 for f in ['fixpc.py', 'fixbinpath.py', 'fixrpath.py', 'Makefile', 'setup_deb.sh', 'purge_build.py', 'update_version.py', 'gen_versioned_debs.py']:
79 files.append( (os.path.join(tmpl_d, f), os.path.join(stack_d, f)) )
80
81
82 if stack_name == 'ros':
83 for f in ['setup_deb.sh', 'Makefile']:
84 f_src = f+'-ros'
85 files.append( (os.path.join(tmpl_d, f_src), os.path.join(stack_d, f)) )
86
87
88 if stack_name == 'ros':
89 for f in ['setup.sh','setup.bash','setup.zsh','.rosinstall']:
90 files.append( (os.path.join(tmpl_d, f), os.path.join(stack_d, f)))
91
92 for src, dst in files:
93 with open(src, 'r') as f:
94 src_text = f.read()
95
96 dst_text = src_text.replace('${ROS_DISTRO_NAME}', distro_name)
97 dst_text = dst_text.replace('${ROS_STACK_NAME}', stack_name)
98 dst_text = dst_text.replace('${ROS_STACK_DEBIAN_NAME}', debian_name)
99 dst_text = dst_text.replace('${ROS_STACK_VERSION}', stack_version)
100 with open(dst, 'w') as f:
101 f.write(dst_text)
102
103
104 s = os.stat(src)
105 os.chmod(dst, s.st_mode)
106
107
108 control_yaml = os.path.join(staging_dir, '%s-%s.yaml'%(stack_name, stack_version))
109 with open(control_yaml, 'r') as f:
110 metadata = yaml.load(f.read())
111 if not type(metadata) == dict:
112 raise Exception("invalid control file: %s\nMetadata is [%s]"%(control_yaml, metadata))
113
114
115 metadata['package'] = debian_name
116 with open(os.path.join(debian_d, 'control'), 'w') as f:
117 f.write(control_file(metadata, distro_name, os_platform_name).encode('utf-8'))
118
119
120 with open(os.path.join(debian_d, 'changelog'), 'w') as f:
121 f.write(changelog_file(metadata, os_platform_name).encode('utf-8'))
122
123
124 build_version='s$BUILD_VERSION'
125
126 with open(os.path.join(debian_d, 'changelog.tmp'), 'w') as f:
127 f.write(changelog_file(metadata, os_platform_name, build_version))
128
129
130 with open(os.path.join(stack_d, '%s-%s.md5'%(stack_name, stack_version)),'w') as mf:
131 with open(os.path.join(staging_dir, '%s-%s.tar.bz2'%(stack_name, stack_version)),'r') as f:
132 m = hashlib.md5()
133 m.update(f.read())
134 mf.write('%s %s\n'%(m.hexdigest(), '../%s-%s.tar.bz2'%(stack_name, stack_version)))
135
136
137 check_call(['dpkg-buildpackage', '-S', '-uc', '-us'], cwd=stack_d)
138
139
140
141 f_name = "%s_%s-0~%s"%(debian_name, stack_version, os_platform_name)
142 files = [os.path.join(staging_dir, f_name+ext) for ext in ('.dsc', '.tar.gz')]
143 for f in files:
144 assert os.path.exists(f), "File: %s does not exist"%f
145
146 return files
147
150
152
153 data = metadata.copy()
154
155 data['date'] = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime())
156 data['platform'] = platform
157 data['supported'] = platform
158 data['build-version'] = build_version
159
160 return """%(package)s (%(version)s-%(build-version)s~%(platform)s) %(supported)s; urgency=low
161
162 * Please see https://ros.org/wiki/%(stack)s/ChangeList
163 \t
164 -- See website <ros-users@code.ros.org> %(date)s
165 \t
166 """%data
167
169 """
170 @return: list of debian package dependencies, or None if not supported on that platform
171 @rtype: [str]
172 """
173
174 if 'rosdeps' not in metadata:
175 return None
176 if platform_name not in metadata['rosdeps']:
177
178 if platform_name == 'maverick' and 'mighty' in metadata['rosdeps']:
179 platform_name = 'mighty'
180 else:
181 return None
182 rosdeps = metadata['rosdeps'][platform_name]
183
184 rosdeps_fixed = []
185 for r in rosdeps:
186 if '=' in r:
187
188 if '*' in r:
189 raise Exception("cannot include glob patterns in debian control file")
190 rosdep_name, version = r.split('=')
191 rosdeps_fixed.append("%s (=%s)"%(rosdep_name, version))
192 else:
193 rosdeps_fixed.append(r)
194 return rosdeps_fixed
195
197 """
198 @return: list of debian stack dependencies
199 @rtype: [str]
200 """
201 stackdeps = metadata.get('depends', [])
202 stackdeps = ['ros-%s-%s'%(distro_name, debianize_name(s)) for s in stackdeps]
203
204 return stackdeps
205
207 url = 'https://code.ros.org/svn/release/download/stacks/%(stack_name)s/%(stack_name)s-%(stack_version)s/%(stack_name)s-%(stack_version)s.yaml'
208 url = url%locals()
209 import urllib2
210 try:
211 return yaml.load(urllib2.urlopen(url))
212 except:
213 raise Exception("Problem fetching yaml info for %s %s (% s).\nThis yaml info is usually created when a release is uploaded. If it is missing, either the stack version is wrong, or the release did not occur correctly."%(stack_name, stack_version, url))
214
216 data = metadata.copy()
217 data['description-full'] = metadata['description-full'].rstrip()
218 data['distro_name'] = distro_name
219 if data['maintainer'].startswith('Maintained by '):
220 data['maintainer'] = data['maintainer'][len('Maintained by '):]
221
222 try:
223 depends = deb_depends(metadata, distro_name, platform_name)
224 stacks = stack_depends(metadata, distro_name, platform_name)
225 if depends is None:
226 raise Exception("stack [%s] does not have valid debian package dependencies for release [%s]"%(metadata['stack'], platform_name))
227 data['all-depends'] = ', '.join(depends + stacks)
228 data['deb-depends'] = ', '.join(depends)
229 except KeyError:
230 raise Exception("stack [%s] does not have rosdeps for release [%s]"%(metadata['stack'], platform_name))
231
232 return """Source: %(package)s
233 Section: unknown
234 Priority: %(priority)s
235 Maintainer: %(maintainer)s
236 Build-Depends: debhelper (>= 5), chrpath, %(all-depends)s
237 Standards-Version: 3.7.2
238 XBC-WG-rosdistro: %(distro_name)s
239
240 Package: %(package)s
241 Architecture: any
242 Depends: ${shlibs:Depends}, ${misc:Depends}, ${rosstack:Depends}, %(deb-depends)s
243 Description: %(description-brief)s
244 %(description-full)s
245 """%data
246
247 -def control_data(stack_name, stack_version, md5sum, stack_file=None):
248 """
249 Generate metadata for control file. Cannot generate debian dependencies as these are platform specific.
250
251 @type stack_name: name of stack
252 @type stack_name: str
253 @type stack_version: stack version id
254 @type stack_version: str
255 @param stack_file: location of stack file, or None to use default rosstack lookup
256 @type stack_file: str
257 """
258 import roslib.stack_manifest
259 if stack_file is None:
260 stack_file = roslib.stack_manifest.stack_file(stack_name)
261 m = roslib.stack_manifest.parse_file(stack_file)
262
263 metadata = {}
264
265 metadata['md5sum'] = md5sum
266 metadata['stack'] = stack_name
267 metadata['package'] = debianize_name(stack_name)
268 metadata['version'] = stack_version
269 metadata['homepage'] = m.url
270 if m.author.startswith('Maintained by '):
271 metadata['maintainer'] = m.author[len('Maintained by '):]
272 else:
273 metadata['maintainer'] = m.author
274 metadata['priority'] = 'optional'
275 if m.brief:
276
277 metadata['description-brief'] = m.brief[:60]
278 else:
279 metadata['description-brief'] = m.brief[:60]
280
281 try:
282 description = convert_html_to_text(m.description).rstrip()
283 except:
284 description = "unknown"
285
286
287 desc_padded = ''
288 for l in description.split('\n'):
289 desc_padded += ' '+l+'\n'
290 metadata['description-full'] = desc_padded.rstrip()
291
292
293
294 metadata['depends'] = [d.stack for d in m.depends]
295 metadata['rosdeps'] = rosdeps = {}
296 for platform in platforms():
297 try:
298 rosdeps[platform] = stack_rosdeps(stack_name, os.path.dirname(stack_file), platform)
299 except Exception as e:
300
301
302 if "cannot generate" in str(e):
303 sys.stderr.write("Error with platform [%s]: %s\n"%(platform, str(e)))
304
305
306
307
308
309 return metadata
310